windows-nt/Source/XPSP1/NT/windows/appcompat/sdbapi/sdbapiplus.c
2020-09-26 16:20:57 +08:00

2289 lines
63 KiB
C

/*++
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"
TCHAR g_szProcessHistory[] = TEXT("__PROCESS_HISTORY");
TCHAR g_szCompatLayer[] = TEXT("__COMPAT_LAYER");
#ifdef _DEBUG_SPEW
extern DBGLEVELINFO g_rgDbgLevelInfo[];
extern PCH g_szDbgLevelUser;
#endif // _DEBUG_SPEW
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 = _tcslen(lpszDest);
int nLenAppend = _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;
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;
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 = _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.
--*/
{
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
BOOL bReturn = FALSE;
PSDBENTRY pEntry;
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 dwMask;
DWORD dwIndex;
DWORD dwCount;
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;
}
}
}
if (pdb == NULL && tiWhich != TAGID_NULL) {
DBGPRINT((sdlError, "SdbTagRefToTagID", "PDB dereferenced by this TAGREF is NULL\n"));
bReturn = FALSE;
}
cleanup:
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;
GUID guidTemp;
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[0];
} 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;
DWORD dwEntrySize;
PFLAGINFO pFlagInfo;
PFLAGINFOENTRY pFlagInfoEntry;
pEntry = pFlagInfoList;
while (pEntry != NULL) {
pEntry->dwEntrySize = 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
//
_tcscpy(&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;
TAGREF trFlagCmdLine;
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(
LPCTSTR pszPath,
LPTSTR pszPathSigned
)
{
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:\\
//
_stprintf(pszPathSigned, _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
--*/
{
UNICODE_STRING ProcessHistoryEnvVarName;
UNICODE_STRING ProcessHistory;
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 = _tcslen(szDir);
NameLen = _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
)
/*++
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;
}
//
// 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;
TAGREF trLayer = TAGREF_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);
}
//
// 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;
}
TCHAR g_szWhiteSpaceDelimiters[] = TEXT(" \t");
BOOL
SdbParseLayerString(
IN PSDBCONTEXT pSdbContext,
IN LPTSTR pszLayerString,
IN PSDBQUERYRESULT pQueryResult,
IN PDWORD pdwLayers,
OUT PBOOL pbAppendLayer // an equivalent of "exclusive" flag
)
{
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
BOOL fSuccess = FALSE;
//
// Skip over and handle special flag characters
// '!' means don't use any EXE entries
// '#' means go ahead and apply layers to system EXEs (we don't handle this)
//
//
// 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) {
//
// ! is processed here
//
if (*pszLayerString == _T('!') && pbAppendLayer) {
*pbAppendLayer = FALSE;
}
pszLayerString++;
}
//
// 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.
//
_tcscpy(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|sdlLogPipe,
"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.
--*/
{
TCHAR szSDBPath[MAX_PATH];
TCHAR szSDBName[MAX_PATH];
DWORD dwLength = sizeof(szSDBName);
BOOL bRet = FALSE;
GUID guidDB;
DWORD dwDatabaseType;
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,
szSDBPath));
//
// 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;
TAGID tiLayer;
TAGREF trLayer;
BOOL bSuccess = FALSE;
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;
}
}
//
// 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);
if (trLayer == TAGREF_NULL) {
DBGPRINT((sdlError,
"SdbpAddMatch",
"Failed to convert 0x%lx to layer ref\n",
tiLayer));
continue;
}
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->dwLayerCount;
tiLayer = SdbFindNextTag(pdb, ptiExes[dwIndex], tiLayer);
}
}
}
if (ptiLayers != NULL) {
for (dwIndex = 0; dwIndex < dwNumLayers; ++dwIndex) {
trLayer = SdbpGetNamedLayerFromExe(pSdbContext, pdb, ptiLayers[dwIndex]);
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->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];
TAGID tiLayer = TAGID_NULL;
DWORD dwLayers = 0;
BOOL bCompatLayer = FALSE;
BOOL bAppendLayer = TRUE; // default behavior is to append to existing fixes
BOOL bReleaseDatabase = FALSE;
BOOL fSuccess = FALSE;
DWORD dwBufferSize;
DWORD dwLocalIndex = 0;
DWORD dwNumExes = 0;
MATCHMODE MatchMode = { 0 };
GUID guidExeID = { 0 };
DWORD dwExeFlags = 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,
&bAppendLayer);
if (!bAppendLayer) {
//
// 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,
&bAppendLayer);
if (!bAppendLayer) {
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.
--*/
{
SdbpCleanupLocalDatabaseSupport(hSDB);
}
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 pszFormat = NULL;
PCH pszMessage= Buffer;
INT cch = CHARCOUNT(Buffer);
va_list arglist;
HANDLE hPipe = INVALID_HANDLE_VALUE;
int iLevel = FILTER_DBG_LEVEL(iLevelAndFlags);
HSDB hSDB = NULL;
BOOL bPipe;
//
// 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.
//
bPipe = !!(iLevelAndFlags & sdlLogPipe);
if (!bPipe && iLevel > g_iShimDebugLevel) {
return 0;
}
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 (bPipe) {
//
// The first arg then is hSDB
//
hSDB = va_arg(arglist, HSDB);
//
// For pipe out we prepend output with [pid:0x%.8lx]
//
nch = sprintf(pchBuffer, "[pid: 0x%.8lx]", GetCurrentProcessId());
pchBuffer += nch;
pszMessage = pchBuffer;
cch -= nch;
}
//
// 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;
}
nch = sprintf(pchBuffer, "[%-4hs]", pchLevel);
pchBuffer += nch;
cch -= nch;
if (pszFunctionName) {
//
// Single-byte char going into UNICODE buffer
//
nch = sprintf(pchBuffer, "[%-20hs] ", pszFunctionName);
pchBuffer += nch;
cch -= nch;
}
//
// _vsntprintf this will not work for UNICODE Win2000
//
nch = _vsnprintf(pchBuffer, cch, pszFormat, arglist); // resolves either to ansi or UNICODE
pchBuffer += nch;
va_end(arglist);
if (nch < 0) { // can't fit into the buffer
return 0;
}
#ifndef WIN32A_MODE
if (bPipe) {
SdbpWriteDebugPipe(hSDB, Buffer);
}
nch = DbgPrint("%s", pszMessage);
STACK_FREE(pszFormat);
#else // WIN32A_MODE
OutputDebugString(pszMessage);
nch = (int)(pchBuffer - pszMessage);
#endif // WIN32A_MODE
#endif // _DEBUG_SPEW
return nch;
}