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.
 
 
 
 
 
 

698 lines
17 KiB

#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;
}