/*++ Copyright (c) 1989-2000 Microsoft Corporation Module Name: ntKMode.c Abstract: This module implements low level primitives for kernel mode implementation. Author: VadimB created sometime in 2000 Revision History: --*/ #include "sdbp.h" #ifdef KERNEL_MODE extern TAG g_rgDirectoryTags[]; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, SdbTagIDToTagRef) #pragma alloc_text(PAGE, SdbTagRefToTagID) #pragma alloc_text(PAGE, SdbInitDatabaseInMemory) #pragma alloc_text(PAGE, SdbpOpenAndMapFile) #pragma alloc_text(PAGE, SdbpUnmapAndCloseFile) #pragma alloc_text(PAGE, SdbpUpcaseUnicodeStringToMultiByteN) #pragma alloc_text(PAGE, SdbpQueryFileDirectoryAttributesNT) #pragma alloc_text(PAGE, SdbpDoesFileExists_U) #pragma alloc_text(PAGE, SdbGetFileInfo) #pragma alloc_text(PAGE, DuplicateUnicodeString) #pragma alloc_text(PAGE, SdbpCreateUnicodeString) #pragma alloc_text(PAGE, SdbpGetFileDirectoryAttributesNT) #endif 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; // // In kernel mode we only support sysmain db // *ptrWhich = tiWhich | PDB_MAIN; bReturn = TRUE; if (!bReturn) { DBGPRINT((sdlError, "SdbTagIDToTagRef", "Bad PDB.\n")); *ptrWhich = TAGREF_NULL; } UNREFERENCED_PARAMETER(hSDB); UNREFERENCED_PARAMETER(pdb); 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; dwMask = trWhich & TAGREF_STRIP_PDB; if (dwMask != PDB_MAIN) { goto cleanup; } tiWhich = trWhich & TAGREF_STRIP_TAGID; pdb = pSdbContext->pdbMain; // // See that we double-check here // 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; } HSDB SdbInitDatabaseInMemory( IN LPVOID pDatabaseImage, IN DWORD dwImageSize ) /*++ Return: BUGBUG: ? Desc: BUGBUG: ? --*/ { PSDBCONTEXT pContext; // // Initialize the context. // pContext = (PSDBCONTEXT)SdbAlloc(sizeof(SDBCONTEXT)); if (pContext == NULL) { DBGPRINT((sdlError, "SdbInitDatabaseInMemory", "Failed to allocate %d bytes for HSDB\n", sizeof(SDBCONTEXT))); return NULL; } // // Now open the database. // pContext->pdbMain = SdbpOpenDatabaseInMemory(pDatabaseImage, dwImageSize); if (pContext->pdbMain == NULL) { DBGPRINT((sdlError, "SdbInitDatabaseInMemory", "Unable to open main database at 0x%x size 0x%x\n", pDatabaseImage, dwImageSize)); goto ErrHandle; } return (HSDB)pContext; ErrHandle: if (pContext != NULL) { if (pContext->pdbMain != NULL) { SdbCloseDatabaseRead(pContext->pdbMain); } SdbFree(pContext); } return NULL; } // // Open and map File // BOOL SdbpOpenAndMapFile( IN LPCWSTR szPath, // pointer to the fully-qualified filename OUT PIMAGEFILEDATA pImageData, // pointer to IMAGEFILEDATA that receives // image-related information IN PATH_TYPE ePathType // ignored ) /*++ Return: TRUE on success, FALSE otherwise. Desc: Opens a file and maps it into memory. --*/ { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING ustrFileName; HANDLE hSection = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; IO_STATUS_BLOCK IoStatusBlock; SIZE_T ViewSize = 0; PVOID pBase = NULL; DWORD dwFlags = 0; FILE_STANDARD_INFORMATION StandardInfo; UNREFERENCED_PARAMETER(ePathType); if (pImageData->dwFlags & IMAGEFILEDATA_PBASEVALID) { // // special case, only headers are valid in our assumption // return TRUE; } // // Initialize return data // if (pImageData->dwFlags & IMAGEFILEDATA_HANDLEVALID) { hFile = pImageData->hFile; if (hFile != INVALID_HANDLE_VALUE) { dwFlags |= IMAGEFILEDATA_NOFILECLOSE; } } RtlZeroMemory(pImageData, sizeof(*pImageData)); pImageData->hFile = INVALID_HANDLE_VALUE; if (hFile == INVALID_HANDLE_VALUE) { // // Open the file // RtlInitUnicodeString(&ustrFileName, szPath); InitializeObjectAttributes(&ObjectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwCreateFile(&hFile, GENERIC_READ, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE, NULL, 0); if (!NT_SUCCESS(Status)) { DBGPRINT((sdlError, "SdbpOpenAndMapFile", "ZwCreateFile failed status 0x%x\n", Status)); return FALSE; } } // // Query file size // Status = ZwQueryInformationFile(hFile, &IoStatusBlock, &StandardInfo, sizeof(StandardInfo), FileStandardInformation); if (!NT_SUCCESS(Status)) { DBGPRINT((sdlError, "SdbpOpenAndMapFile", "ZwQueryInformationFile (EOF) failed Status 0x%x\n", Status)); if (!(dwFlags & IMAGEFILEDATA_NOFILECLOSE)) { ZwClose(hFile); } return FALSE; } InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwCreateSection(&hSection, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ, &ObjectAttributes, NULL, PAGE_READONLY, SEC_COMMIT, hFile); if (!NT_SUCCESS(Status)) { DBGPRINT((sdlError, "SdbpOpenAndMapFile", "ZwOpenSectionFailed status 0x%x\n", Status)); if (!(dwFlags & IMAGEFILEDATA_NOFILECLOSE)) { ZwClose(hFile); } return FALSE; } Status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBase, 0L, 0L, NULL, &ViewSize, ViewUnmap, 0L, PAGE_READONLY); if (!NT_SUCCESS(Status)) { DBGPRINT((sdlError, "SdbpMapFile", "NtMapViewOfSection failed Status 0x%x\n", Status)); ZwClose(hSection); if (!(dwFlags & IMAGEFILEDATA_NOFILECLOSE)) { ZwClose(hFile); } return FALSE; } pImageData->hFile = hFile; pImageData->dwFlags = dwFlags; pImageData->hSection = hSection; pImageData->pBase = pBase; pImageData->ViewSize = ViewSize; pImageData->FileSize = StandardInfo.EndOfFile.QuadPart; return TRUE; } BOOL SdbpUnmapAndCloseFile( IN PIMAGEFILEDATA pImageData // pointer to IMAGEFILEDATE - image-related information ) /*++ Return: TRUE on success, FALSE otherwise. Desc: Closes and unmaps an opened file. --*/ { BOOL bSuccess = TRUE; NTSTATUS Status; if (pImageData->dwFlags & IMAGEFILEDATA_PBASEVALID) { // externally supplied pointer RtlZeroMemory(pImageData, sizeof(*pImageData)); return TRUE; } if (pImageData->pBase != NULL) { Status = ZwUnmapViewOfSection(NtCurrentProcess(), pImageData->pBase); if (!NT_SUCCESS(Status)) { bSuccess = FALSE; DBGPRINT((sdlError, "SdbpCloseAndUnmapFile", "ZwUnmapViewOfSection failed Status 0x%x\n", Status)); } pImageData->pBase = NULL; } if (pImageData->hSection != NULL) { Status = ZwClose(pImageData->hSection); if (!NT_SUCCESS(Status)) { bSuccess = FALSE; DBGPRINT((sdlError, "SdbpCloseAndUnmapFile", "ZwClose on section failed Status 0x%x\n", Status)); } pImageData->hSection = NULL; } if (pImageData->dwFlags & IMAGEFILEDATA_NOFILECLOSE) { pImageData->hFile = INVALID_HANDLE_VALUE; } else { if (pImageData->hFile != INVALID_HANDLE_VALUE) { Status = ZwClose(pImageData->hFile); if (!NT_SUCCESS(Status)) { bSuccess = FALSE; DBGPRINT((sdlError, "SdbpCloseAndUnmapFile", "ZwClose on file failed Status 0x%x\n", Status)); } pImageData->hFile = INVALID_HANDLE_VALUE; } } return bSuccess; } NTSTATUS SdbpUpcaseUnicodeStringToMultiByteN( OUT LPSTR lpszDest, // dest buffer IN DWORD dwSize, // size in characters, excluding unicode_null IN LPCWSTR lpszSrc // source ) /*++ Return: TRUE on success, FALSE otherwise. Desc: Convert up to dwSize characters from Unicode to ANSI. --*/ { ANSI_STRING strDest; UNICODE_STRING ustrSource; NTSTATUS Status; UNICODE_STRING ustrUpcaseSource = { 0 }; USHORT DestBufSize = (USHORT)dwSize * sizeof(WCHAR); RtlInitUnicodeString(&ustrSource, lpszSrc); STACK_ALLOC(ustrUpcaseSource.Buffer, ustrSource.MaximumLength); if (ustrUpcaseSource.Buffer == NULL) { DBGPRINT((sdlError, "SdbpUnicodeToMultiByteN", "Failed to allocate %d bytes on the stack\n", (DWORD)ustrSource.MaximumLength)); return STATUS_NO_MEMORY; } ustrUpcaseSource.MaximumLength = ustrSource.MaximumLength; ustrUpcaseSource.Length = 0; Status = RtlUpcaseUnicodeString(&ustrUpcaseSource, &ustrSource, FALSE); if (!NT_SUCCESS(Status)) { DBGPRINT((sdlError, "SdbpUnicodeToMultiByteN", "RtlUpcaseUnicodeString failed Status 0x%x\n", Status)); goto Done; } if (ustrUpcaseSource.Length > DestBufSize) { ustrUpcaseSource.Length = DestBufSize; } strDest.Buffer = lpszDest; strDest.MaximumLength = DestBufSize + sizeof(UNICODE_NULL); strDest.Length = 0; Status = RtlUnicodeStringToAnsiString(&strDest, &ustrUpcaseSource, FALSE); if (!NT_SUCCESS(Status)) { DBGPRINT((sdlError, "SdbpUnicodeToMultiByteN", "RtlUnicodeStringToAnsiString failed Status 0x%x\n", Status)); } Done: if (ustrUpcaseSource.Buffer != NULL) { STACK_FREE(ustrUpcaseSource.Buffer); } return Status; } BOOL SdbpQueryFileDirectoryAttributesNT( PIMAGEFILEDATA pImageData, PFILEDIRECTORYATTRIBUTES pFileDirectoryAttributes ) /*++ Return: TRUE on success, FALSE otherwise. Desc: BUGBUG: ? --*/ { LARGE_INTEGER liFileSize; liFileSize.QuadPart = pImageData->FileSize; pFileDirectoryAttributes->dwFlags |= FDA_FILESIZE; pFileDirectoryAttributes->dwFileSizeHigh = liFileSize.HighPart; pFileDirectoryAttributes->dwFileSizeLow = liFileSize.LowPart; return TRUE; } BOOL SdbpDoesFileExists_U( LPCWSTR pwszPath ) /*++ Return: TRUE on success, FALSE otherwise. Desc: BUGBUG: ? --*/ { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING ustrFileName; HANDLE hFile; NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; RtlInitUnicodeString(&ustrFileName, pwszPath); InitializeObjectAttributes(&ObjectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwCreateFile(&hFile, STANDARD_RIGHTS_REQUIRED | FILE_READ_ATTRIBUTES, &ObjectAttributes, &IoStatusBlock, NULL, // AllocationSize FILE_ATTRIBUTE_NORMAL, // FileAttributes FILE_SHARE_READ, // Share Access FILE_OPEN, // Create Disposition FILE_NON_DIRECTORY_FILE | // Create Options FILE_SYNCHRONOUS_IO_NONALERT, NULL, // EaBuffer 0); // EaLength if (!NT_SUCCESS(Status)) { DBGPRINT((sdlError, "SdbpDoesFileExists_U", "Failed to create file. Status 0x%x\n", Status)); return FALSE; } ZwClose(hFile); return TRUE; } PVOID SdbGetFileInfo( IN HSDB hSDB, IN LPCWSTR pwszFilePath, IN HANDLE hFile, // handle for the file in question IN LPVOID pImageBase, // image base for this file IN DWORD dwImageSize, IN BOOL bNoCache ) /*++ Return: BUGBUG: ? Desc: Create and link a new entry in a file attribute cache. --*/ { PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB; LPCWSTR FullPath = pwszFilePath; PFILEINFO pFileInfo = NULL; UNICODE_STRING FullPathU; if (!bNoCache) { pFileInfo = FindFileInfo(pContext, FullPath); } if (pFileInfo == NULL) { if (hFile != INVALID_HANDLE_VALUE || pImageBase != NULL || SdbpDoesFileExists_U(FullPath)) { RtlInitUnicodeString(&FullPathU, FullPath); pFileInfo = CreateFileInfo(pContext, FullPathU.Buffer, FullPathU.Length / sizeof(WCHAR), hFile, pImageBase, dwImageSize, bNoCache); } } return (PVOID)pFileInfo; } WCHAR* DuplicateUnicodeString( PUNICODE_STRING pStr, PUSHORT pLength // pLength is an allocated length ) /*++ Return: BUGBUG: ? Desc: BUGBUG: ? --*/ { WCHAR* pBuffer = NULL; USHORT Length = 0; if (pStr != NULL && pStr->Length > 0) { Length = pStr->Length + sizeof(UNICODE_NULL); pBuffer = (WCHAR*)SdbAlloc(Length); if (pBuffer == NULL) { DBGPRINT((sdlError, "DuplicateUnicodeString", "Failed to allocate %d bytes\n", Length)); return NULL; } RtlMoveMemory(pBuffer, pStr->Buffer, pStr->Length); pBuffer[pStr->Length/sizeof(WCHAR)] = UNICODE_NULL; } if (pLength != NULL) { *pLength = Length; } return pBuffer; } BOOL SdbpCreateUnicodeString( PUNICODE_STRING pStr, LPCWSTR lpwsz ) /*++ Return: BUGBUG: ? Desc: BUGBUG: ? --*/ { USHORT Length; UNICODE_STRING ustrSrc; RtlZeroMemory(pStr, sizeof(*pStr)); RtlInitUnicodeString(&ustrSrc, lpwsz); pStr->Buffer = DuplicateUnicodeString(&ustrSrc, &Length); pStr->Length = ustrSrc.Length; pStr->MaximumLength = Length; return pStr->Buffer != NULL; } BOOL SdbpGetFileDirectoryAttributesNT( OUT PFILEINFO pFileInfo, IN PIMAGEFILEDATA pImageData ) /*++ Return: TRUE on success, FALSE otherwise. Desc: This function retrieves the header attributes for the specified file. --*/ { BOOL bSuccess = FALSE; FILEDIRECTORYATTRIBUTES fda; int i; bSuccess = SdbpQueryFileDirectoryAttributesNT(pImageData, &fda); if (!bSuccess) { DBGPRINT((sdlInfo, "SdbpGetFileDirectoryAttributesNT", "No file directory attributes available.\n")); goto Done; } if (fda.dwFlags & FDA_FILESIZE) { assert(fda.dwFileSizeHigh == 0); SdbpSetAttribute(pFileInfo, TAG_SIZE, &fda.dwFileSizeLow); } Done: if (!bSuccess) { for (i = 0; g_rgDirectoryTags[i] != 0; ++i) { SdbpSetAttribute(pFileInfo, g_rgDirectoryTags[i], NULL); } } return bSuccess; } // // Disable warnings for _snprintf. // We can't use strsafe in here because // ntoskrnl would have to link to strsafe.lib. // #pragma warning (disable : 4995) #ifdef _DEBUG_SPEW extern DBGLEVELINFO g_rgDbgLevelInfo[]; extern PCH g_szDbgLevelUser; #endif // _DEBUG_SPEW int __cdecl ShimDbgPrint( int iLevel, PCH pszFunctionName, PCH Format, ... ) { int nch = 0; #ifdef _DEBUG_SPEW PCH pszFormat = NULL; va_list arglist; ULONG Level = 0; int i; CHAR szPrefix[64]; PCH pchBuffer = szPrefix; PCH pchLevel = NULL; PREPARE_FORMAT(pszFormat, Format); if (pszFormat == NULL) { // // Can't convert format for debug output // return 0; } // // 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 = _snprintf(pchBuffer, sizeof(szPrefix), "[%-4hs]", pchLevel); pchBuffer += nch; if (pszFunctionName) { // // Single-byte char going into UNICODE buffer // nch = _snprintf(pchBuffer, sizeof(szPrefix) - nch, "[%-30hs] ", pszFunctionName); pchBuffer += nch; } switch (iLevel) { case sdlError: Level = (1 << DPFLTR_ERROR_LEVEL) | DPFLTR_MASK; break; case sdlWarning: Level = (1 << DPFLTR_WARNING_LEVEL) | DPFLTR_MASK; break; case sdlInfo: Level = (1 << DPFLTR_TRACE_LEVEL) | DPFLTR_MASK; break; } va_start(arglist, Format); nch = (int)vDbgPrintExWithPrefix(szPrefix, DPFLTR_NTOSPNP_ID, Level, pszFormat, arglist); va_end(arglist); STACK_FREE(pszFormat); #else UNREFERENCED_PARAMETER(iLevel); UNREFERENCED_PARAMETER(pszFunctionName); UNREFERENCED_PARAMETER(Format); #endif // _DEBUG_SPEW return nch; } #pragma warning (default : 4995) #endif // KERNEL_MODE