|
|
#include "nt.h"
#include "ntdef.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "ntrtl.h"
#include "ntosp.h"
#include "stdio.h"
#include "sxs-rtl.h"
#include "fasterxml.h"
#include "skiplist.h"
#include "namespacemanager.h"
#include "xmlstructure.h"
#include "sxsid.h"
#include "xmlassert.h"
#include "manifestinspection.h"
void RtlTraceNtSuccessFailure( PCSTR pcszStatement, NTSTATUS FailureCode, PCSTR pcszFileName, LONG LineNumber ) { CHAR SmallBuffer[512]; STRING s; s.Buffer = SmallBuffer; s.Length = s.MaximumLength = (USHORT)_snprintf( "%s(%d): NTSTATUS 0x%08lx from '%s'\n", NUMBER_OF(SmallBuffer), pcszFileName, LineNumber, FailureCode, pcszStatement);
#if 0 // When we move to kernel mode, we should turn this on - for now, let's just use OutputDebugStringA
DebugPrint(&s, 0, 0); #else
printf(SmallBuffer); #endif
}
#undef NT_SUCCESS
#define NT_SUCCESS(q) (((status = (q)) < 0) ? (RtlTraceNtSuccessFailure(#q, status, __FILE__, __LINE__), FALSE) : TRUE)
NTSTATUS RtlpGenerateIdentityFromAttributes( IN PXML_TOKENIZATION_STATE pState, IN PXMLDOC_ATTRIBUTE pAttributeList, IN ULONG ulAttributes, IN OUT PUNICODE_STRING pusDiskName, IN OUT PUNICODE_STRING pusTextualIdentity ) /*++
Parameters:
pState - State of xml tokenization/parsing that can be used to extract strings and other stuff from the attributes in pAttributeList
pAttributeList - Array of pointers to PXMLDOC_ATTRIBUTE structures that represent the identity attributes
ulAttributes - Number of attributes in pAttributeList
pusDiskName - Pointer to a UNICODE_STRING whose MaxLength is enough to contain 104 wchars. On exit, pusDiskName->Buffer will contain the on-disk identity of this set of attributes, and pusDiskName->Length will be the length of said data. (Not null terminated!)
pusTextualIdentity - Pointer to a UNICODE_STRING which will be filled out on exit with the 'textual identity' of this set of attributes. --*/ { NTSTATUS status = STATUS_SUCCESS; ULONG ulHash = 0;
return status; }
NTSTATUS RtlGetSxsAssemblyRoot( ULONG ulFlags, PUNICODE_STRING pusTempPathname, PUSHORT pulRequiredChars ) { static const UNICODE_STRING s_us_WinSxsRoot = RTL_CONSTANT_STRING(L"\\WinSxS\\"); NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING NtSystemRoot; USHORT usLength;
//
// If there was a buffer, zero out the length so a naive caller won't
// accidentally use it.
//
if (pusTempPathname) { pusTempPathname->Length = 0; }
RtlInitUnicodeString(&NtSystemRoot, USER_SHARED_DATA->NtSystemRoot); usLength = NtSystemRoot.Length + s_us_WinSxsRoot.Length;
if (pulRequiredChars) *pulRequiredChars = usLength;
// No buffer, or it's too small completely, then oops
if (!pusTempPathname || (pusTempPathname->MaximumLength < usLength)) { status = STATUS_BUFFER_TOO_SMALL; } // Otherwise, start copying
else { PWCHAR pwszCursor = pusTempPathname->Buffer; RtlCopyMemory(pwszCursor, NtSystemRoot.Buffer, NtSystemRoot.Length); RtlCopyMemory((PCHAR)pwszCursor + NtSystemRoot.Length, s_us_WinSxsRoot.Buffer, s_us_WinSxsRoot.Length); pusTempPathname->Length = usLength; }
return status; }
// Installtemp identifiers are a combination of the current system time in
// a "nicely formatted" format, plus some 16-bit hex uniqueness value
#define CHARS_IN_INSTALLTEMP_IDENT (NUMBER_OF("yyyymmddhhmmssllll.xxxx") - 1)
NTSTATUS RtlpCreateWinSxsTempPath( ULONG ulFlags, PUNICODE_STRING pusTempPath, WCHAR wchStatic, USHORT uscchStatus ) { NTSTATUS status = STATUS_SUCCESS; USHORT ulLength = 0;
if ((pusTempPath == NULL) || (ulFlags != 0)) { return STATUS_INVALID_PARAMETER; }
//
// Get the length of the root path
//
status = RtlGetSxsAssemblyRoot(0, NULL, &ulLength); if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_TOO_SMALL)) { return status; } ulLength += 1 + CHARS_IN_INSTALLTEMP_IDENT;
//
// Ensure there's space
//
if (ulLength >= pusTempPath->MaximumLength) { pusTempPath->MaximumLength = ulLength; return STATUS_BUFFER_TOO_SMALL; }
//
// Get it again.
//
status = RtlGetSxsAssemblyRoot(0, pusTempPath, &ulLength); return status; }
NTSTATUS RtlpPrepareForAssemblyInstall( ULONG ulFlags, PUNICODE_STRING pusTempPathname ) { NTSTATUS status = STATUS_SUCCESS; USHORT ulRequired = 0;
// Find out how long the 'root' path is.
status = RtlGetSxsAssemblyRoot(0, NULL, &ulRequired);
// Now let's find out how long our id is going to be
return status; }
const static WCHAR s_rgchBase64Encoding[] = { L'A', L'B', L'C', L'D', L'E', L'F', L'G', L'H', L'I', L'J', L'K', // 11
L'L', L'M', L'N', L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', // 22
L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', L'e', L'f', L'g', // 33
L'h', L'i', L'j', L'k', L'l', L'm', L'n', L'o', L'p', L'q', L'r', // 44
L's', L't', L'u', L'v', L'w', L'x', L'y', L'z', L'0', L'1', L'2', // 55
L'3', L'4', L'5', L'6', L'7', L'8', L'9', L'+', L'/' // 64
};
NTSTATUS RtlBase64Encode( PVOID pvBuffer, SIZE_T cbBuffer, PWSTR pwszEncoded, PSIZE_T pcchEncoded ) { SIZE_T cchRequiredEncodingSize; SIZE_T iInput, iOutput; //
// Null input buffer, null output size pointer, and a nonzero
// encoded size with a null output buffer are all invalid
// parameters
//
if (!pvBuffer || !pcchEncoded || ((*pcchEncoded > 0) && !pwszEncoded)) { return STATUS_INVALID_PARAMETER; }
//
// Make sure the buffer is large enough
//
cchRequiredEncodingSize = ((cbBuffer + 2) / 3) * 4;
if (*pcchEncoded < cchRequiredEncodingSize) { *pcchEncoded = cchRequiredEncodingSize; return STATUS_BUFFER_TOO_SMALL; }
//
// Convert the input buffer bytes through the encoding table and
// out into the output buffer.
//
iInput = iOutput = 0; while (iInput < cbBuffer) { const UCHAR uc0 = ((PUCHAR)pvBuffer)[iInput++]; const UCHAR uc1 = (iInput < cbBuffer) ? ((PUCHAR)pvBuffer)[iInput++] : 0; const UCHAR uc2 = (iInput < cbBuffer) ? ((PUCHAR)pvBuffer)[iInput++] : 0;
pwszEncoded[iOutput++] = s_rgchBase64Encoding[uc0 >> 2]; pwszEncoded[iOutput++] = s_rgchBase64Encoding[((uc0 << 4) & 0x30) | ((uc1 >> 4) & 0xf)]; pwszEncoded[iOutput++] = s_rgchBase64Encoding[((uc1 << 2) & 0x3c) | ((uc2 >> 6) & 0x3)]; pwszEncoded[iOutput++] = s_rgchBase64Encoding[uc2 & 0x3f]; }
//
// Fill in leftover bytes at the end
//
switch(cbBuffer % 3) { case 0: break; //
// One byte out of three, add padding and fall through
//
case 1: pwszEncoded[iOutput - 2] = L'='; //
// Two bytes out of three, add padding.
case 2: pwszEncoded[iOutput - 1] = L'='; break; }
return STATUS_SUCCESS; }
NTSTATUS RtlInstallAssembly( ULONG ulFlags, PCWSTR pcwszManifestPath ) { SIZE_T cbFileSize; PVOID pvFileBase = 0; NTSTATUS status; PRTL_MANIFEST_CONTENT_RAW pRawContent = NULL; XML_TOKENIZATION_STATE TokenizationStateUsed; UNICODE_STRING usFilePath;
status = RtlSxsInitializeManifestRawContent(RTLIMS_GATHER_FILES, &pRawContent, NULL, 0); if (!NT_SUCCESS(status)) { goto Exit; }
//
// Get ahold of the file
//
status = RtlOpenAndMapEntireFile(pcwszManifestPath, &pvFileBase, &cbFileSize); if (!NT_SUCCESS(status)) { goto Exit; }
//
// We should have found some files
//
status = RtlInspectManifestStream( RTLIMS_GATHER_FILES, pvFileBase, cbFileSize, pRawContent, &TokenizationStateUsed); if (!NT_SUCCESS(status)) goto Exit;
//
// Validate that the assembly
Exit: if (pRawContent) { RtlSxsDestroyManifestContent(pRawContent); } RtlUnmapViewOfFile(pvFileBase);
return status; }
BOOLEAN RtlDosPathNameToNtPathName_Ustr( IN PCUNICODE_STRING DosFileNameString, OUT PUNICODE_STRING NtFileName, OUT PWSTR *FilePart OPTIONAL, OUT PRTL_RELATIVE_NAME_U RelativeName OPTIONAL );
NTSTATUS RtlOpenAndMapEntireFile( PCWSTR pcwszFilePath, PVOID *ppvMappedView, PSIZE_T pcbFileSize ) { HANDLE SectionHandle = INVALID_HANDLE_VALUE; HANDLE FileHandle = INVALID_HANDLE_VALUE; UNICODE_STRING ObjectName; OBJECT_ATTRIBUTES ObjA; POBJECT_ATTRIBUTES pObjA; ACCESS_MASK DesiredAccess; ULONG ulAllocationAttributes; NTSTATUS status; IO_STATUS_BLOCK IOStatusBlock; BOOLEAN Translation; SIZE_T FileSize; FILE_STANDARD_INFORMATION Info;
if (pcbFileSize) { *pcbFileSize = 0; }
if (ppvMappedView) { *ppvMappedView = NULL; }
if (!ARGUMENT_PRESENT(pcwszFilePath)) { return STATUS_INVALID_PARAMETER; }
if (!ARGUMENT_PRESENT(pcbFileSize)) { return STATUS_INVALID_PARAMETER; } if (!ARGUMENT_PRESENT(ppvMappedView)) { return STATUS_INVALID_PARAMETER; }
Translation = RtlDosPathNameToNtPathName_U( pcwszFilePath, &ObjectName, NULL, NULL);
if (!Translation) { return STATUS_NOT_FOUND; }
//
// Open the file requested
//
InitializeObjectAttributes( &ObjA, &ObjectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = NtOpenFile( &FileHandle, FILE_GENERIC_READ, &ObjA, &IOStatusBlock, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_NON_DIRECTORY_FILE);
if (!NT_SUCCESS(status)) { goto ErrorExit; }
status = NtQueryInformationFile( FileHandle, &IOStatusBlock, &Info, sizeof(Info), FileStandardInformation);
if (!NT_SUCCESS(status)) { goto ErrorExit; }
*pcbFileSize = (SIZE_T)Info.EndOfFile.QuadPart;
status = NtCreateSection( &SectionHandle, SECTION_MAP_READ | SECTION_QUERY, NULL, NULL, PAGE_READONLY, SEC_COMMIT, FileHandle);
if (!NT_SUCCESS(status)) { goto ErrorExit; }
//
// Don't need the file object anymore, unmap it
//
status = NtClose(FileHandle); FileHandle = INVALID_HANDLE_VALUE;;
*ppvMappedView = NULL;
//
// Map the whole file
//
status = NtMapViewOfSection( SectionHandle, NtCurrentProcess(), ppvMappedView, 0, // Zero bits
0, // Committed size
NULL, // SectionOffset
pcbFileSize, // Size of this file, in bytes
ViewShare, 0, PAGE_READONLY);
status = NtClose(SectionHandle); SectionHandle = INVALID_HANDLE_VALUE;
//
// Reset this - the NtMapViewOfSection allocates on page granularity
//
*pcbFileSize = (SIZE_T)Info.EndOfFile.QuadPart;
Exit: return status;
ErrorExit: if (FileHandle != INVALID_HANDLE_VALUE) { NtClose(FileHandle); FileHandle = INVALID_HANDLE_VALUE; }
if (SectionHandle != INVALID_HANDLE_VALUE) { NtClose(SectionHandle); SectionHandle = INVALID_HANDLE_VALUE; }
if (ppvMappedView && (*ppvMappedView != NULL)) { NTSTATUS newstatus = NtUnmapViewOfSection(NtCurrentProcess(), *ppvMappedView);
//
// Failed while failing
//
if (!NT_SUCCESS(newstatus)) { }
*pcbFileSize = 0; }
goto Exit; }
NTSTATUS RtlUnmapViewOfFile( PVOID pvBase ) { NTSTATUS status;
status = NtUnmapViewOfSection( NtCurrentProcess(), pvBase);
return status; }
NTSTATUS FASTCALL RtlMiniHeapAlloc( SIZE_T cb, PVOID *ppvAllocated, PVOID pvContext ) { PRTL_MINI_HEAP pContent = (PRTL_MINI_HEAP)pvContext;
if ((pContent == NULL) || (ppvAllocated == NULL)) { return STATUS_INVALID_PARAMETER; }
if (pContent->cbAvailableBytes < cb) { return g_DefaultAllocator.pfnAlloc(cb, ppvAllocated, NULL); } else { *ppvAllocated = pContent->pvNextAvailableByte; pContent->cbAvailableBytes -= cb; pContent->pvNextAvailableByte = (PUCHAR)pContent->pvNextAvailableByte + cb;
return STATUS_SUCCESS; } }
NTSTATUS FASTCALL RtlMiniHeapFree( PVOID pvAllocation, PVOID pvContext ) { PRTL_MINI_HEAP pContent = (PRTL_MINI_HEAP)pvContext;
if ((pvAllocation < pContent->pvAllocationBase) || (pvAllocation >= (PVOID)((PUCHAR)pContent->pvAllocationBase + pContent->cbOriginalSize))) { return g_DefaultAllocator.pfnFree(pvAllocation, NULL); } else { return STATUS_SUCCESS; } }
NTSTATUS FASTCALL RtlInitializeMiniHeap( PRTL_MINI_HEAP MiniHeap, PVOID pvTargetRegion, SIZE_T cbRegionSize ) { if (!MiniHeap || !(pvTargetRegion || (cbRegionSize == 0))) { return STATUS_INVALID_PARAMETER; }
MiniHeap->pvNextAvailableByte = pvTargetRegion; MiniHeap->pvAllocationBase = pvTargetRegion; MiniHeap->cbAvailableBytes = cbRegionSize; MiniHeap->cbOriginalSize = cbRegionSize;
return STATUS_SUCCESS; }
NTSTATUS FASTCALL RtlInitializeMiniHeapInPlace( PVOID pvRegion, SIZE_T cbOriginalSize, PRTL_MINI_HEAP *ppMiniHeap ) { PRTL_MINI_HEAP pMiniHeapTemp = NULL; if (!ppMiniHeap) return STATUS_INVALID_PARAMETER;
*ppMiniHeap = NULL;
if (!(pvRegion || (cbOriginalSize == 0))) { return STATUS_INVALID_PARAMETER; }
if (cbOriginalSize < sizeof(RTL_MINI_HEAP)) { return STATUS_NO_MEMORY; }
pMiniHeapTemp = (PRTL_MINI_HEAP)pvRegion; pMiniHeapTemp->cbAvailableBytes = cbOriginalSize - sizeof(RTL_MINI_HEAP); pMiniHeapTemp->cbOriginalSize = pMiniHeapTemp->cbAvailableBytes; pMiniHeapTemp->pvAllocationBase = pMiniHeapTemp + 1; pMiniHeapTemp->pvNextAvailableByte = pMiniHeapTemp->pvAllocationBase;
*ppMiniHeap = pMiniHeapTemp; return STATUS_SUCCESS; }
NTSTATUS RtlpConvertHexStringToBytes( PUNICODE_STRING pSourceString, PBYTE pbTarget, SIZE_T cbTarget ) { NTSTATUS status = STATUS_SUCCESS; PCWSTR pcSource = pSourceString->Buffer; ULONG ul = 0;
if (cbTarget < (pSourceString->Length / (2 * sizeof(WCHAR)))) { return STATUS_BUFFER_TOO_SMALL; } else if ((pSourceString->Length % sizeof(WCHAR)) != 0) { return STATUS_INVALID_PARAMETER; }
for (ul = 0; ul < (pSourceString->Length / sizeof(pSourceString->Buffer[0])); ul += 2) {
BYTE bvLow, bvHigh; const WCHAR wchFirst = *pcSource++; const WCHAR wchSecond = *pcSource++;
//
// Set the high nibble
//
switch (wchFirst) { case L'0': case L'1': case L'2': case L'3': case L'4': case L'5': case L'6': case L'7': case L'8': case L'9': bvHigh = wchFirst - L'0'; break;
case L'a': case L'b': case L'c': case L'd': case L'e': case L'f': bvHigh = (wchFirst - L'a') + 0x10; break;
case L'A': case L'B': case L'C': case L'D': case L'E': case L'F': bvHigh = (wchFirst - L'A') + 0x10; break;
default: return STATUS_INVALID_PARAMETER; }
//
// Set the high nibble
//
switch (wchSecond) { case L'0': case L'1': case L'2': case L'3': case L'4': case L'5': case L'6': case L'7': case L'8': case L'9': bvLow = wchSecond - L'0'; break;
case L'a': case L'b': case L'c': case L'd': case L'e': case L'f': bvLow = (wchSecond - L'a') + 0x10; break;
case L'A': case L'B': case L'C': case L'D': case L'E': case L'F': bvLow = (wchSecond - L'A') + 0x10; break;
default: return STATUS_INVALID_PARAMETER; }
pbTarget[ul / 2] = (bvHigh << 4) | bvLow; }
return STATUS_SUCCESS; }
|