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.
1802 lines
48 KiB
1802 lines
48 KiB
/*++
|
|
|
|
Copyright (c) 1998-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
misc.h
|
|
|
|
Abstract:
|
|
|
|
This module contains miscellaneous constants & declarations.
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 10-Jun-1998
|
|
Henry Sanders (henrysa) 17-Jun-1998 Merge with old httputil.h
|
|
Paul McDaniel (paulmcd) 30-Mar-1999 added refcounted eresource
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#ifndef _MISC_H_
|
|
#define _MISC_H_
|
|
|
|
|
|
|
|
#define UL_MAX_HTTP_STATUS_CODE 999
|
|
#define UL_MAX_HTTP_STATUS_CODE_LENGTH 3
|
|
|
|
#define HTTP_PREFIX_ANSI "http://"
|
|
#define HTTP_PREFIX_ANSI_LENGTH (sizeof(HTTP_PREFIX_ANSI)-sizeof(CHAR))
|
|
#define HTTPS_PREFIX_ANSI "https://"
|
|
#define HTTPS_PREFIX_ANSI_LENGTH (sizeof(HTTPS_PREFIX_ANSI)-sizeof(CHAR))
|
|
|
|
#define HTTP_PREFIX_COLON_INDEX 4 // the colon location for http: (+4)
|
|
#define HTTPS_PREFIX_COLON_INDEX 5 // the colon location for https: (+5)
|
|
|
|
//
|
|
// Note that the length of the strong wildcard prefix is the same as
|
|
// that of the (weak) wildcard prefix.
|
|
//
|
|
|
|
#define HTTPS_WILD_PREFIX L"https://*:"
|
|
#define HTTPS_WILD_PREFIX_LENGTH (sizeof(HTTPS_WILD_PREFIX)-sizeof(WCHAR))
|
|
#define HTTP_WILD_PREFIX L"http://*:"
|
|
#define HTTP_WILD_PREFIX_LENGTH (sizeof(HTTP_WILD_PREFIX)-sizeof(WCHAR))
|
|
#define HTTPS_STRONG_WILD_PREFIX L"https://+:"
|
|
#define HTTP_STRONG_WILD_PREFIX L"http://+:"
|
|
|
|
#define HTTP_IP_PREFIX L"http://"
|
|
#define HTTP_IP_PREFIX_LENGTH (sizeof(HTTP_IP_PREFIX)-sizeof(WCHAR))
|
|
#define HTTPS_IP_PREFIX L"https://"
|
|
#define HTTPS_IP_PREFIX_LENGTH (sizeof(HTTPS_IP_PREFIX)-sizeof(WCHAR))
|
|
|
|
NTSTATUS
|
|
InitializeHttpUtil(
|
|
VOID
|
|
);
|
|
|
|
|
|
//
|
|
// Our presumed cache-line size.
|
|
//
|
|
|
|
#define CACHE_LINE_SIZE UL_CACHE_LINE
|
|
|
|
|
|
//
|
|
// # of 100ns ticks per second ( 1ns = (1 / (10^9))s )
|
|
//
|
|
|
|
#define C_NS_TICKS_PER_SEC ((LONGLONG) (10 * 1000 * 1000))
|
|
|
|
//
|
|
// # of 100ns ticks per minute ( 1ns = (1 / ((10^9) * 60)) min )
|
|
//
|
|
|
|
#define C_NS_TICKS_PER_MIN ((LONGLONG) (C_NS_TICKS_PER_SEC * 60))
|
|
|
|
//
|
|
// # of millisecs per hour ( 1 ms = (1 / ((10^3) * 60 * 60)) hour )
|
|
//
|
|
|
|
#define C_MS_TICKS_PER_HOUR ((LONGLONG) (1000 * 60 * 60))
|
|
|
|
//
|
|
// # of 100ns ticks per milli second ( 1ns = (1 / (10^4)) milli sec )
|
|
//
|
|
|
|
#define C_NS_TICKS_PER_MSEC ((LONGLONG) (10 * 1000))
|
|
|
|
//
|
|
// # of seconds per year (aprox)
|
|
// 1 year = (60 sec/min * 60 min/hr * 24 hr/day * 365 day/year)
|
|
//
|
|
|
|
#define C_SECS_PER_YEAR ((ULONG) (60 * 60 * 24 * 365))
|
|
|
|
//
|
|
// Alignment macros.
|
|
//
|
|
|
|
#define ROUND_UP( val, pow2 ) \
|
|
( ( (ULONG_PTR)(val) + (pow2) - 1 ) & ~( (pow2) - 1 ) )
|
|
|
|
|
|
//
|
|
// Macros for swapping the bytes in a long and a short.
|
|
//
|
|
|
|
#define SWAP_LONG RtlUlongByteSwap
|
|
#define SWAP_SHORT RtlUshortByteSwap
|
|
|
|
|
|
#define VALID_BOOLEAN_VALUE(x) ((x) == TRUE || (x) == FALSE)
|
|
|
|
|
|
//
|
|
// Context values stored in PFILE_OBJECT->FsContext2 to identify a handle
|
|
// as a control channel, filter channel or an app pool.
|
|
//
|
|
// BUGBUG: Can these be spoofed?
|
|
//
|
|
|
|
#define UL_CONTROL_CHANNEL_CONTEXT ((PVOID) MAKE_SIGNATURE('CTRL'))
|
|
#define UL_CONTROL_CHANNEL_CONTEXT_X ((PVOID) MAKE_SIGNATURE('Xctr'))
|
|
#define UL_FILTER_CHANNEL_CONTEXT ((PVOID) MAKE_SIGNATURE('FLTR'))
|
|
#define UL_FILTER_CHANNEL_CONTEXT_X ((PVOID) MAKE_SIGNATURE('Xflt'))
|
|
#define UL_APP_POOL_CONTEXT ((PVOID) MAKE_SIGNATURE('APPP'))
|
|
#define UL_APP_POOL_CONTEXT_X ((PVOID) MAKE_SIGNATURE('Xapp'))
|
|
#define UC_SERVER_CONTEXT ((PVOID) MAKE_SIGNATURE('SERV'))
|
|
#define UC_SERVER_CONTEXT_X ((PVOID) MAKE_SIGNATURE('Xerv'))
|
|
|
|
#define IS_SERVER( pFileObject ) \
|
|
( (pFileObject)->FsContext2 == UC_SERVER_CONTEXT )
|
|
|
|
#define IS_EX_SERVER( pFileObject ) \
|
|
( (pFileObject)->FsContext2 == UC_SERVER_CONTEXT_X )
|
|
|
|
#define MARK_VALID_SERVER( pFileObject ) \
|
|
( (pFileObject)->FsContext2 = UC_SERVER_CONTEXT )
|
|
|
|
#define MARK_INVALID_SERVER( pFileObject ) \
|
|
( (pFileObject)->FsContext2 = UC_SERVER_CONTEXT_X )
|
|
|
|
#define IS_CONTROL_CHANNEL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 == UL_CONTROL_CHANNEL_CONTEXT )
|
|
|
|
#define IS_EX_CONTROL_CHANNEL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 == UL_CONTROL_CHANNEL_CONTEXT_X )
|
|
|
|
#define MARK_VALID_CONTROL_CHANNEL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 = UL_CONTROL_CHANNEL_CONTEXT )
|
|
|
|
#define MARK_INVALID_CONTROL_CHANNEL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 = UL_CONTROL_CHANNEL_CONTEXT_X )
|
|
|
|
#define GET_CONTROL_CHANNEL( pFileObject ) \
|
|
((PUL_CONTROL_CHANNEL)((pFileObject)->FsContext))
|
|
|
|
#define GET_PP_CONTROL_CHANNEL( pFileObject ) \
|
|
((PUL_CONTROL_CHANNEL *)&((pFileObject)->FsContext))
|
|
|
|
#define IS_FILTER_PROCESS( pFileObject ) \
|
|
( (pFileObject)->FsContext2 == UL_FILTER_CHANNEL_CONTEXT )
|
|
|
|
#define IS_EX_FILTER_PROCESS( pFileObject ) \
|
|
( (pFileObject)->FsContext2 == UL_FILTER_CHANNEL_CONTEXT_X )
|
|
|
|
#define MARK_VALID_FILTER_CHANNEL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 = UL_FILTER_CHANNEL_CONTEXT )
|
|
|
|
#define MARK_INVALID_FILTER_CHANNEL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 = UL_FILTER_CHANNEL_CONTEXT_X )
|
|
|
|
#define GET_FILTER_PROCESS( pFileObject ) \
|
|
((PUL_FILTER_PROCESS)((pFileObject)->FsContext))
|
|
|
|
#define GET_PP_FILTER_PROCESS( pFileObject ) \
|
|
((PUL_FILTER_PROCESS *)&((pFileObject)->FsContext))
|
|
|
|
#define IS_APP_POOL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 == UL_APP_POOL_CONTEXT )
|
|
|
|
#define IS_EX_APP_POOL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 == UL_APP_POOL_CONTEXT_X )
|
|
|
|
#define MARK_VALID_APP_POOL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 = UL_APP_POOL_CONTEXT )
|
|
|
|
#define MARK_INVALID_APP_POOL( pFileObject ) \
|
|
( (pFileObject)->FsContext2 = UL_APP_POOL_CONTEXT_X )
|
|
|
|
#define GET_APP_POOL_PROCESS( pFileObject ) \
|
|
((PUL_APP_POOL_PROCESS)((pFileObject)->FsContext))
|
|
|
|
#define GET_PP_APP_POOL_PROCESS( pFileObject ) \
|
|
((PUL_APP_POOL_PROCESS *)&((pFileObject)->FsContext))
|
|
|
|
#define IS_APP_POOL_FO( pFileObject ) \
|
|
((pFileObject->DeviceObject->DriverObject == g_UlDriverObject) && \
|
|
(IS_APP_POOL(pFileObject)))
|
|
|
|
#define IS_FILTER_PROCESS_FO(pFileObject) \
|
|
((pFileObject->DeviceObject->DriverObject == g_UlDriverObject) && \
|
|
(IS_FILTER_PROCESS(pFileObject)))
|
|
|
|
//
|
|
// A locked doubly-linked list
|
|
//
|
|
|
|
typedef struct DECLSPEC_ALIGN(UL_CACHE_LINE) _LOCKED_LIST_HEAD
|
|
{
|
|
UL_SPIN_LOCK SpinLock;
|
|
ULONG Count;
|
|
LIST_ENTRY ListHead;
|
|
|
|
} LOCKED_LIST_HEAD, *PLOCKED_LIST_HEAD;
|
|
|
|
//
|
|
// Manipulators for LOCKED_LIST_HEADs
|
|
//
|
|
|
|
__inline
|
|
VOID
|
|
UlInitalizeLockedList(
|
|
IN PLOCKED_LIST_HEAD pListHead,
|
|
IN PSTR pListName
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(pListName);
|
|
InitializeListHead(&pListHead->ListHead);
|
|
pListHead->Count = 0;
|
|
UlInitializeSpinLock(&pListHead->SpinLock, pListName);
|
|
|
|
} // UlInitalizeLockedList
|
|
|
|
__inline
|
|
VOID
|
|
UlDestroyLockedList(
|
|
IN PLOCKED_LIST_HEAD pListHead
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(pListHead);
|
|
ASSERT(IsListEmpty(&pListHead->ListHead));
|
|
ASSERT(pListHead->Count == 0);
|
|
ASSERT(UlDbgSpinLockUnowned(&pListHead->SpinLock));
|
|
|
|
} // UlDestroyLockedList
|
|
|
|
__inline
|
|
BOOLEAN
|
|
UlLockedListInsertHead(
|
|
IN PLOCKED_LIST_HEAD pListHead,
|
|
IN PLIST_ENTRY pListEntry,
|
|
IN ULONG ListLimit
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
UlAcquireSpinLock(&pListHead->SpinLock, &OldIrql);
|
|
|
|
ASSERT(NULL == pListEntry->Flink);
|
|
|
|
if (HTTP_LIMIT_INFINITE != ListLimit && (pListHead->Count + 1) >= ListLimit)
|
|
{
|
|
UlReleaseSpinLock(&pListHead->SpinLock, OldIrql);
|
|
return FALSE;
|
|
}
|
|
|
|
pListHead->Count += 1;
|
|
InsertHeadList(
|
|
&pListHead->ListHead,
|
|
pListEntry
|
|
);
|
|
|
|
UlReleaseSpinLock(&pListHead->SpinLock, OldIrql);
|
|
|
|
return TRUE;
|
|
|
|
} // UlLockedListInsertHead
|
|
|
|
__inline
|
|
BOOLEAN
|
|
UlLockedListInsertTail(
|
|
IN PLOCKED_LIST_HEAD pListHead,
|
|
IN PLIST_ENTRY pListEntry,
|
|
IN ULONG ListLimit
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
UlAcquireSpinLock(&pListHead->SpinLock, &OldIrql);
|
|
|
|
ASSERT(NULL == pListEntry->Flink);
|
|
|
|
if (HTTP_LIMIT_INFINITE != ListLimit && (pListHead->Count + 1) >= ListLimit)
|
|
{
|
|
UlReleaseSpinLock(&pListHead->SpinLock, OldIrql);
|
|
return FALSE;
|
|
}
|
|
|
|
pListHead->Count += 1;
|
|
InsertTailList(
|
|
&pListHead->ListHead,
|
|
pListEntry
|
|
);
|
|
|
|
UlReleaseSpinLock(&pListHead->SpinLock, OldIrql);
|
|
|
|
return TRUE;
|
|
|
|
} // UlLockedListInsertTail
|
|
|
|
__inline
|
|
PLIST_ENTRY
|
|
UlLockedListRemoveHead(
|
|
IN PLOCKED_LIST_HEAD pListHead
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY pEntry = NULL;
|
|
|
|
UlAcquireSpinLock(&pListHead->SpinLock, &OldIrql);
|
|
|
|
if (!IsListEmpty(&pListHead->ListHead))
|
|
{
|
|
pEntry = RemoveHeadList(&pListHead->ListHead);
|
|
ASSERT(NULL != pEntry);
|
|
pEntry->Flink = NULL;
|
|
|
|
pListHead->Count -= 1;
|
|
ASSERT(HTTP_LIMIT_INFINITE != pListHead->Count);
|
|
}
|
|
|
|
UlReleaseSpinLock(&pListHead->SpinLock, OldIrql);
|
|
|
|
return pEntry;
|
|
|
|
} // UlLockedListRemoveHead
|
|
|
|
__inline
|
|
BOOLEAN
|
|
UlLockedListRemoveEntry(
|
|
IN PLOCKED_LIST_HEAD pListHead,
|
|
IN PLIST_ENTRY pListEntry
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
UlAcquireSpinLock(&pListHead->SpinLock, &OldIrql);
|
|
|
|
if (NULL == pListEntry->Flink)
|
|
{
|
|
UlReleaseSpinLock(&pListHead->SpinLock, OldIrql);
|
|
return FALSE;
|
|
}
|
|
|
|
RemoveEntryList(pListEntry);
|
|
pListEntry->Flink = NULL;
|
|
|
|
pListHead->Count -= 1;
|
|
ASSERT(HTTP_LIMIT_INFINITE != pListHead->Count);
|
|
|
|
UlReleaseSpinLock(&pListHead->SpinLock, OldIrql);
|
|
|
|
return TRUE;
|
|
|
|
} // UlLockedListRemoveEntry
|
|
|
|
//
|
|
// Miscellaneous validators, etc.
|
|
//
|
|
|
|
#define IS_VALID_DEVICE_OBJECT( pDeviceObject ) \
|
|
( ((pDeviceObject) != NULL) && \
|
|
((pDeviceObject)->Type == IO_TYPE_DEVICE) && \
|
|
((pDeviceObject)->Size == sizeof(DEVICE_OBJECT)) )
|
|
|
|
#define IS_VALID_FILE_OBJECT( pFileObject ) \
|
|
( ((pFileObject) != NULL) && \
|
|
((pFileObject)->Type == IO_TYPE_FILE) && \
|
|
((pFileObject)->Size == sizeof(FILE_OBJECT)) )
|
|
|
|
#define IS_VALID_IRP( pIrp ) \
|
|
( ((pIrp) != NULL) && \
|
|
((pIrp)->Type == IO_TYPE_IRP) && \
|
|
((pIrp)->Size >= IoSizeOfIrp((pIrp)->StackCount)) )
|
|
|
|
//
|
|
// IP Based routing token looks like L"https://1.1.1.1:80:1.1.1.1".
|
|
// Space is calculated including the terminated null and the second
|
|
// column. It is in bytes.
|
|
//
|
|
|
|
#define MAX_IP_BASED_ROUTING_TOKEN_LENGTH \
|
|
(HTTPS_IP_PREFIX_LENGTH \
|
|
+ MAX_IP_ADDR_AND_PORT_STRING_LEN * sizeof(WCHAR) \
|
|
+ sizeof(WCHAR) + MAX_IP_ADDR_PLUS_BRACKETS_STRING_LEN * sizeof(WCHAR) \
|
|
+ sizeof(WCHAR))
|
|
|
|
//
|
|
// Make sure that the maximum possible IP Based Routing token can fit to the
|
|
// default provided routing token space in the request structure. This is
|
|
// necessary to avoid the memory allocation per hit, when there is an IP bound
|
|
// site in the cgroup tree.
|
|
//
|
|
|
|
C_ASSERT(DEFAULT_MAX_ROUTING_TOKEN_LENGTH >= MAX_IP_BASED_ROUTING_TOKEN_LENGTH);
|
|
NTSTATUS
|
|
TimeFieldsToHttpDate(
|
|
IN PTIME_FIELDS pTime,
|
|
OUT PWSTR pBuffer,
|
|
IN ULONG BufferLength
|
|
);
|
|
|
|
BOOLEAN
|
|
StringTimeToSystemTime(
|
|
IN PCSTR pTimeString,
|
|
IN USHORT TimeStringLength,
|
|
OUT LARGE_INTEGER *pTime
|
|
);
|
|
|
|
ULONG
|
|
HttpUnicodeToUTF8(
|
|
IN PCWSTR lpSrcStr,
|
|
IN LONG cchSrc,
|
|
OUT LPSTR lpDestStr,
|
|
IN LONG cchDest
|
|
);
|
|
|
|
NTSTATUS
|
|
HttpUTF8ToUnicode(
|
|
IN LPCSTR lpSrcStr,
|
|
IN LONG cchSrc,
|
|
OUT LPWSTR lpDestStr,
|
|
IN OUT PLONG pcchDest,
|
|
IN ULONG dwFlags
|
|
);
|
|
|
|
typedef enum _FIND_ETAG_STATUS
|
|
{
|
|
ETAG_FOUND,
|
|
ETAG_NOT_FOUND,
|
|
ETAG_PARSE_ERROR,
|
|
} FIND_ETAG_STATUS;
|
|
|
|
FIND_ETAG_STATUS
|
|
FindInETagList(
|
|
IN PUCHAR pLocalETag,
|
|
IN PUCHAR pETagList,
|
|
IN BOOLEAN fWeakCompare
|
|
);
|
|
|
|
USHORT
|
|
HostAddressAndPortToString(
|
|
OUT PUCHAR IpAddressString,
|
|
IN PVOID TdiAddress,
|
|
IN USHORT TdiAddressType
|
|
);
|
|
|
|
USHORT
|
|
HostAddressAndPortToStringW(
|
|
PWCHAR IpAddressString,
|
|
PVOID TdiAddress,
|
|
USHORT TdiAddressType
|
|
);
|
|
|
|
USHORT
|
|
HostAddressToStringW(
|
|
OUT PWCHAR IpAddressStringW,
|
|
IN PVOID TdiAddress,
|
|
IN USHORT TdiAddressType
|
|
);
|
|
|
|
USHORT
|
|
HostAddressAndPortToRoutingTokenW(
|
|
OUT PWCHAR IpAddressStringW,
|
|
IN PVOID TdiAddress,
|
|
IN USHORT TdiAddressType
|
|
);
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Stores the decimal representation of an unsigned 32-bit
|
|
number in a character buffer, followed by a terminator
|
|
character. Returns a pointer to the next position in the
|
|
output buffer, to make appending strings easy; i.e., you
|
|
can use the result of UlStrPrintUlong as the argument to the
|
|
next call to UlStrPrintUlong. Note: the string is >not<
|
|
zero-terminated unless you passed in '\0' as chTerminator
|
|
|
|
Arguments:
|
|
|
|
psz - output buffer; assumed to be large enough to hold the number.
|
|
|
|
n - the number to print into psz, a 32-bit unsigned integer
|
|
|
|
chTerminator - character to append after the decimal representation of n
|
|
|
|
Return Value:
|
|
|
|
pointer to end of string
|
|
|
|
History:
|
|
|
|
GeorgeRe 19-Sep-2000
|
|
|
|
--***************************************************************************/
|
|
__inline
|
|
PCHAR
|
|
UlStrPrintUlong(
|
|
OUT PCHAR psz,
|
|
IN ULONG n,
|
|
IN CHAR chTerminator)
|
|
{
|
|
CHAR digits[MAX_ULONG_STR];
|
|
int i = 0;
|
|
|
|
ASSERT(psz != NULL);
|
|
|
|
digits[i++] = chTerminator;
|
|
|
|
// Build the string in reverse
|
|
do
|
|
{
|
|
digits[i++] = (CHAR) (n % 10) + '0';
|
|
n /= 10;
|
|
} while (n != 0);
|
|
|
|
while (--i >= 0)
|
|
*psz++ = digits[i];
|
|
|
|
// Back up to the nul terminator, if present
|
|
if (chTerminator == '\0')
|
|
{
|
|
--psz;
|
|
ASSERT(*psz == '\0');
|
|
}
|
|
|
|
return psz;
|
|
} // UlStrPrintUlong
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Identical to the above function except it writes to a WCHAR buffer and
|
|
it pads zeros to the beginning of the number.
|
|
|
|
--***************************************************************************/
|
|
__inline
|
|
PWCHAR
|
|
UlStrPrintUlongW(
|
|
OUT PWCHAR pwsz,
|
|
IN ULONG n,
|
|
IN LONG padding,
|
|
IN WCHAR wchTerminator)
|
|
{
|
|
WCHAR digits[MAX_ULONG_STR];
|
|
int i = 0;
|
|
|
|
ASSERT(pwsz != NULL);
|
|
|
|
digits[i++] = wchTerminator;
|
|
|
|
// Build the string in reverse
|
|
do
|
|
{
|
|
digits[i++] = (WCHAR) (n % 10) + L'0';
|
|
n /= 10;
|
|
} while (n != 0);
|
|
|
|
// Padd Zeros to the beginning
|
|
while( padding && --padding >= (i-1))
|
|
*pwsz++ = L'0';
|
|
|
|
// Reverse back
|
|
while (--i >= 0)
|
|
*pwsz++ = digits[i];
|
|
|
|
// Back up to the nul terminator, if present
|
|
if (wchTerminator == L'\0')
|
|
{
|
|
--pwsz;
|
|
ASSERT(*pwsz == L'\0');
|
|
}
|
|
|
|
return pwsz;
|
|
} // UlStrPrintUlongW
|
|
|
|
__inline
|
|
PCHAR
|
|
UlStrPrintUlongPad(
|
|
OUT PCHAR psz,
|
|
IN ULONG n,
|
|
IN LONG padding,
|
|
IN CHAR chTerminator)
|
|
{
|
|
CHAR digits[MAX_ULONG_STR];
|
|
int i = 0;
|
|
|
|
ASSERT(psz != NULL);
|
|
|
|
digits[i++] = chTerminator;
|
|
|
|
// Build the string in reverse
|
|
do
|
|
{
|
|
digits[i++] = (CHAR) (n % 10) + '0';
|
|
n /= 10;
|
|
} while (n != 0);
|
|
|
|
// Padd Zeros to the beginning
|
|
while( padding && --padding >= (i-1))
|
|
*psz++ = '0';
|
|
|
|
// Reverse back
|
|
while (--i >= 0)
|
|
*psz++ = digits[i];
|
|
|
|
// Back up to the nul terminator, if present
|
|
if (chTerminator == '\0')
|
|
{
|
|
--psz;
|
|
ASSERT(*psz == '\0');
|
|
}
|
|
|
|
return psz;
|
|
} // UlStrPrintUlongPad
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Stores the decimal representation of an unsigned 64-bit
|
|
number in a character buffer, followed by a terminator
|
|
character. Returns a pointer to the next position in the
|
|
output buffer, to make appending strings easy; i.e., you
|
|
can use the result of UlStrPrintUlonglong as the argument to the
|
|
next call to UlStrPrintUlonglong. Note: the string is >not<
|
|
zero-terminated unless you passed in '\0' as chTerminator
|
|
|
|
Arguments:
|
|
|
|
psz - output buffer; assumed to be large enough to hold the number.
|
|
|
|
n - the number to print into psz, a 64-bit unsigned integer
|
|
|
|
chTerminator - character to append after the decimal representation of n
|
|
|
|
Return Value:
|
|
|
|
pointer to end of string
|
|
|
|
History:
|
|
|
|
GeorgeRe 19-Sep-2000
|
|
|
|
--***************************************************************************/
|
|
__inline
|
|
PCHAR
|
|
UlStrPrintUlonglong(
|
|
OUT PCHAR psz,
|
|
IN ULONGLONG n,
|
|
IN CHAR chTerminator)
|
|
{
|
|
CHAR digits[MAX_ULONGLONG_STR];
|
|
int i;
|
|
|
|
if (n <= ULONG_MAX)
|
|
{
|
|
// If this is a 32-bit integer, it's faster to use the
|
|
// 32-bit routine.
|
|
return UlStrPrintUlong(psz, (ULONG)n, chTerminator);
|
|
}
|
|
|
|
ASSERT(psz != NULL);
|
|
|
|
i = 0;
|
|
digits[i++] = chTerminator;
|
|
|
|
// Build the string in reverse
|
|
do
|
|
{
|
|
digits[i++] = (CHAR) (n % 10) + '0';
|
|
n /= 10;
|
|
} while (n != 0);
|
|
|
|
while (--i >= 0)
|
|
*psz++ = digits[i];
|
|
|
|
// Back up to the nul terminator, if present
|
|
if (chTerminator == '\0')
|
|
{
|
|
--psz;
|
|
ASSERT(*psz == '\0');
|
|
}
|
|
|
|
return psz;
|
|
} // UlStrPrintUlonglong
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Stores a string in a character buffer, followed by a
|
|
terminator character. Returns a pointer to the next position
|
|
in the output buffer, to make appending strings easy; i.e.,
|
|
you can use the result of UlStrPrintStr as the argument to the
|
|
next call to UlStrPrintStr. Note: the string is >not<
|
|
zero-terminated unless you passed in '\0' as chTerminator
|
|
|
|
Arguments:
|
|
|
|
pszOutput - output buffer; assumed to be large enough to hold the number.
|
|
|
|
pszInput - input string
|
|
|
|
chTerminator - character to append after the input string
|
|
|
|
Return Value:
|
|
|
|
pointer to end of string
|
|
|
|
History:
|
|
|
|
GeorgeRe 19-Sep-2000
|
|
|
|
--***************************************************************************/
|
|
__inline
|
|
PCHAR
|
|
UlStrPrintStr(
|
|
OUT PCHAR pszOutput,
|
|
IN const CHAR* pszInput,
|
|
IN CHAR chTerminator)
|
|
{
|
|
ASSERT(pszOutput != NULL);
|
|
ASSERT(pszInput != NULL);
|
|
|
|
// copy the input string
|
|
while (*pszInput != '\0')
|
|
*pszOutput++ = *pszInput++;
|
|
|
|
*pszOutput = chTerminator;
|
|
|
|
// Move past the terminator character unless it's a nul
|
|
if (chTerminator != '\0')
|
|
++pszOutput;
|
|
|
|
return pszOutput;
|
|
} // UlStrPrintStr
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Converts an V4 Ip address to string in the provided buffer.
|
|
|
|
Arguments:
|
|
|
|
psz - Pointer to the buffer
|
|
RawAddress - IP address structure from TDI / UL_CONNECTION
|
|
chTerminator - The terminator char will be appended to the end
|
|
|
|
Return:
|
|
|
|
The number of bytes copied to destination buffer.
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
PCHAR
|
|
UlStrPrintIP(
|
|
OUT PCHAR psz,
|
|
IN const VOID* pTdiAddress,
|
|
IN USHORT TdiAddressType,
|
|
IN CHAR chTerminator
|
|
)
|
|
{
|
|
if (TdiAddressType == TDI_ADDRESS_TYPE_IP)
|
|
{
|
|
PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) pTdiAddress);
|
|
struct in_addr IPv4Addr
|
|
= * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr;
|
|
|
|
psz = RtlIpv4AddressToStringA(&IPv4Addr, psz);
|
|
}
|
|
else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6)
|
|
{
|
|
PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) pTdiAddress);
|
|
struct in6_addr IPv6Addr
|
|
= * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0];
|
|
|
|
psz = RtlIpv6AddressToStringA(&IPv6Addr, psz);
|
|
|
|
// Write Scope ID
|
|
*psz++ = '%';
|
|
psz = UlStrPrintUlong(psz, pIPv6Address->sin6_scope_id, '\0');
|
|
}
|
|
else
|
|
{
|
|
ASSERT(! "Unexpected TdiAddressType");
|
|
*psz++ = '?';
|
|
}
|
|
|
|
*psz = chTerminator;
|
|
|
|
// Move past the terminator character unless it's a nul
|
|
if (chTerminator != '\0')
|
|
++psz;
|
|
|
|
return psz;
|
|
} // UlStrPrintIP
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Converts an V4 or V6 Ip address to string in the provided buffer.
|
|
Provided seperator is inserted between Ip and Port and also
|
|
appended after the port.
|
|
|
|
String is * NOT * going to be null terminated.
|
|
|
|
Arguments:
|
|
|
|
psz - Pointer to the buffer
|
|
RawAddress - IP address structure from TDI / UL_CONNECTION
|
|
chSeperator - the seperator character
|
|
|
|
Return:
|
|
|
|
The char pointer pointing after the last written seperator.
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
PCHAR
|
|
UlStrPrintIPAndPort(
|
|
OUT PCHAR psz,
|
|
IN const VOID* pTdiAddress,
|
|
IN USHORT TdiAddressType,
|
|
IN CHAR chSeperator
|
|
)
|
|
{
|
|
if (TdiAddressType == TDI_ADDRESS_TYPE_IP)
|
|
{
|
|
PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) pTdiAddress);
|
|
struct in_addr IPv4Addr
|
|
= * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr;
|
|
USHORT IpPortNum = SWAP_SHORT(pIPv4Address->sin_port);
|
|
|
|
psz = RtlIpv4AddressToStringA(&IPv4Addr, psz);
|
|
*psz++ = chSeperator;
|
|
psz = UlStrPrintUlong(psz, IpPortNum, '\0');
|
|
}
|
|
else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6)
|
|
{
|
|
PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) pTdiAddress);
|
|
struct in6_addr IPv6Addr
|
|
= * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0];
|
|
USHORT IpPortNum = SWAP_SHORT(pIPv6Address->sin6_port);
|
|
|
|
psz = RtlIpv6AddressToStringA(&IPv6Addr, psz);
|
|
|
|
// Write Scope ID
|
|
*psz++ = '%';
|
|
psz = UlStrPrintUlong(psz, pIPv6Address->sin6_scope_id, '\0');
|
|
|
|
*psz++ = chSeperator;
|
|
psz = UlStrPrintUlong(psz, IpPortNum, '\0');
|
|
}
|
|
else
|
|
{
|
|
ASSERT(! "Unexpected TdiAddressType");
|
|
*psz++ = '?';
|
|
}
|
|
|
|
*psz++ = chSeperator;
|
|
|
|
return psz;
|
|
|
|
} // UlStrPrintIPAndPort
|
|
|
|
__inline
|
|
VOID
|
|
CopyTdiAddrToSockAddr(
|
|
IN USHORT TdiAddressType,
|
|
IN const VOID* pTdiAddress,
|
|
OUT struct sockaddr* pSockAddress
|
|
)
|
|
{
|
|
if (TdiAddressType == TDI_ADDRESS_TYPE_IP)
|
|
{
|
|
const PTDI_ADDRESS_IP pIPv4Address
|
|
= (const PTDI_ADDRESS_IP) pTdiAddress;
|
|
struct sockaddr_in *pSockAddrIPv4
|
|
= (struct sockaddr_in*) pSockAddress;
|
|
|
|
pSockAddrIPv4->sin_family = TdiAddressType;
|
|
pSockAddrIPv4->sin_port = pIPv4Address->sin_port;
|
|
pSockAddrIPv4->sin_addr.s_addr
|
|
= (UNALIGNED ULONG) pIPv4Address->in_addr;
|
|
RtlCopyMemory(
|
|
&pSockAddrIPv4->sin_zero[0],
|
|
&pIPv4Address->sin_zero[0],
|
|
8 * sizeof(UCHAR)
|
|
);
|
|
}
|
|
else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6)
|
|
{
|
|
const PTDI_ADDRESS_IP6 pIPv6Address
|
|
= (const PTDI_ADDRESS_IP6) pTdiAddress;
|
|
struct sockaddr_in6 *pSockAddrIPv6
|
|
= (struct sockaddr_in6*) pSockAddress;
|
|
|
|
pSockAddrIPv6->sin6_family = TdiAddressType;
|
|
pSockAddrIPv6->sin6_port = pIPv6Address->sin6_port;
|
|
pSockAddrIPv6->sin6_flowinfo
|
|
= (UNALIGNED ULONG) pIPv6Address->sin6_flowinfo;
|
|
RtlCopyMemory(
|
|
&pSockAddrIPv6->sin6_addr,
|
|
&pIPv6Address->sin6_addr[0],
|
|
8 * sizeof(USHORT)
|
|
);
|
|
pSockAddrIPv6->sin6_scope_id
|
|
= (UNALIGNED ULONG) pIPv6Address->sin6_scope_id;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(! "Unexpected TdiAddressType");
|
|
}
|
|
} // CopyTdiAddrToSockAddr
|
|
|
|
|
|
__inline
|
|
PCHAR
|
|
UlStrPrintProtocolStatus(
|
|
OUT PCHAR psz,
|
|
IN USHORT HttpStatusCode,
|
|
IN CHAR chTerminator
|
|
)
|
|
{
|
|
ASSERT(HttpStatusCode <= UL_MAX_HTTP_STATUS_CODE);
|
|
|
|
//
|
|
// Build ASCII representation of 3-digit status code
|
|
// in reverse order: units, tens, hundreds
|
|
//
|
|
|
|
psz[2] = '0' + (CHAR)(HttpStatusCode % 10);
|
|
HttpStatusCode /= 10;
|
|
|
|
psz[1] = '0' + (CHAR)(HttpStatusCode % 10);
|
|
HttpStatusCode /= 10;
|
|
|
|
psz[0] = '0' + (CHAR)(HttpStatusCode % 10);
|
|
|
|
psz[3] = chTerminator;
|
|
|
|
return psz + 4;
|
|
} // UlStrPrintProtocolStatus
|
|
|
|
|
|
|
|
__inline
|
|
VOID
|
|
UlProbeForRead(
|
|
IN const VOID* Address,
|
|
IN SIZE_T Length,
|
|
IN ULONG Alignment,
|
|
IN KPROCESSOR_MODE RequestorMode
|
|
)
|
|
{
|
|
ASSERT((Alignment == 1) || (Alignment == 2) ||
|
|
(Alignment == 4) || (Alignment == 8) ||
|
|
(Alignment == 16));
|
|
|
|
UlTraceVerbose(IOCTL,
|
|
("http!UlProbeForRead: "
|
|
"%Id bytes @ %p, Align = %lu, Mode = '%c'.\n",
|
|
Length, Address, Alignment,
|
|
(RequestorMode != KernelMode) ? 'U' : 'K'
|
|
));
|
|
|
|
if (RequestorMode != KernelMode)
|
|
{
|
|
// ASSERT(Length == 0 || (LONG_PTR) Address > 0);
|
|
|
|
// ProbeForRead will throw an exception if we probe kernel-mode data
|
|
ProbeForRead(Address, Length, Alignment);
|
|
}
|
|
else if (Length != 0)
|
|
{
|
|
// Check alignment
|
|
if ( ( ((ULONG_PTR) Address) & (Alignment - 1)) != 0 )
|
|
ExRaiseDatatypeMisalignment();
|
|
}
|
|
} // UlProbeForRead
|
|
|
|
|
|
|
|
__inline
|
|
VOID
|
|
UlProbeForWrite(
|
|
IN PVOID Address,
|
|
IN SIZE_T Length,
|
|
IN ULONG Alignment,
|
|
IN KPROCESSOR_MODE RequestorMode
|
|
)
|
|
{
|
|
ASSERT((Alignment == 1) || (Alignment == 2) ||
|
|
(Alignment == 4) || (Alignment == 8) ||
|
|
(Alignment == 16));
|
|
|
|
UlTraceVerbose(IOCTL,
|
|
("http!UlProbeForWrite: "
|
|
"%Id bytes @ %p, Align = %lu, Mode = '%c'.\n",
|
|
Length, Address, Alignment,
|
|
(RequestorMode != KernelMode) ? 'U' : 'K'
|
|
));
|
|
|
|
if (RequestorMode != KernelMode)
|
|
{
|
|
// ASSERT(Length == 0 || (LONG_PTR) Address > 0);
|
|
|
|
// ProbeForWrite will throw an exception if we probe kernel-mode data
|
|
ProbeForWrite(Address, Length, Alignment);
|
|
}
|
|
else if (Length != 0)
|
|
{
|
|
// Check alignment
|
|
if ( ( ((ULONG_PTR) Address) & (Alignment - 1)) != 0 )
|
|
ExRaiseDatatypeMisalignment();
|
|
}
|
|
} // UlProbeForWrite
|
|
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Probes an ANSI string and validates its length and accessibility.
|
|
This MUST be called from within an exception handler, as it
|
|
will throw exceptions if the data is invalid.
|
|
|
|
Arguments:
|
|
|
|
pStr - Pointer to the ANSI string to be validated.
|
|
ByteLength - Length in bytes of pStr, excluding the trailing '\0'.
|
|
RequestorMode - UserMode or KernelMode
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
VOID
|
|
UlProbeAnsiString(
|
|
IN PCSTR pStr,
|
|
IN USHORT ByteLength,
|
|
IN KPROCESSOR_MODE RequestorMode
|
|
)
|
|
{
|
|
UlTraceVerbose(IOCTL,
|
|
("http!UlProbeAnsiString: "
|
|
"%hu bytes @ %p, "
|
|
"Mode='%c'.\n",
|
|
ByteLength, pStr,
|
|
((RequestorMode != KernelMode) ? 'U' : 'K')
|
|
));
|
|
|
|
// String cannot be empty or NULL.
|
|
if (0 == ByteLength || NULL == pStr)
|
|
{
|
|
ExRaiseStatus(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UlProbeForRead(
|
|
pStr,
|
|
(SIZE_T) ByteLength,
|
|
sizeof(CHAR),
|
|
RequestorMode
|
|
);
|
|
|
|
} // UlProbeAnsiString
|
|
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Probes a WCHAR string and validates its length and accessibility.
|
|
This MUST be called from within an exception handler, as it
|
|
will throw exceptions if the data is invalid.
|
|
|
|
Arguments:
|
|
|
|
pStr - Pointer to the WCHAR string to be validated.
|
|
ByteLength - Length in bytes of pStr, excluding the trailing L'\0'.
|
|
RequestorMode - UserMode or KernelMode
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
VOID
|
|
UlProbeWideString(
|
|
IN PCWSTR pStr,
|
|
IN USHORT ByteLength,
|
|
IN KPROCESSOR_MODE RequestorMode
|
|
)
|
|
{
|
|
UlTraceVerbose(IOCTL,
|
|
("http!UlProbeWideString: "
|
|
"%hu bytes (%hu) WCHARs @ %p,"
|
|
"Mode = '%c'.\n",
|
|
ByteLength,
|
|
ByteLength / sizeof(WCHAR),
|
|
pStr,
|
|
((RequestorMode != KernelMode) ? 'U' : 'K')
|
|
));
|
|
|
|
// String cannot be empty or NULL.
|
|
// ByteLength must be even.
|
|
// Data must be WCHAR-aligned.
|
|
if (0 == ByteLength || NULL == pStr
|
|
|| (ByteLength & (sizeof(WCHAR) - 1)) != 0
|
|
|| (((ULONG_PTR) pStr) & (sizeof(WCHAR) - 1)) != 0)
|
|
{
|
|
ExRaiseStatus(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
UlProbeForRead(
|
|
pStr,
|
|
(SIZE_T) ByteLength,
|
|
sizeof(WCHAR),
|
|
RequestorMode
|
|
);
|
|
|
|
} // UlProbeWideString
|
|
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Probes a UNICODE_STRING and validates its members. And captures down
|
|
to a kernel buffer.
|
|
|
|
If this function returns success, caller should clean up the allocated
|
|
Unicode buffer by calling UlFreeCapturedUnicodeString(), once it's done
|
|
with it.
|
|
|
|
Arguments:
|
|
|
|
pSrc - Pointer to the UNICODE_STRING to be validated.
|
|
The UNICODE_STRING struct should live in kernel mode
|
|
(local stack copy), but the Buffer should be in user
|
|
mode address space, unless RequestorMode == KernelMode.
|
|
|
|
pDst - Pointer to the UNICODE_STRING to hold the captured user
|
|
buffer. Caller must have initialized this before passing
|
|
in.
|
|
|
|
AllocationLimit - User string will be refused if it is exceeding this limit.
|
|
Expressed in WCHARs. If zero, no size check is done.
|
|
|
|
RequestorMode - UserMode or KernelMode.
|
|
|
|
--***************************************************************************/
|
|
|
|
__inline
|
|
NTSTATUS
|
|
UlProbeAndCaptureUnicodeString(
|
|
IN PCUNICODE_STRING pSrc,
|
|
IN KPROCESSOR_MODE RequestorMode,
|
|
OUT PUNICODE_STRING pDst,
|
|
IN const USHORT AllocationLimit // In WCHARS, optional
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PWSTR pKernelBuffer = NULL;
|
|
|
|
ASSERT(NULL != pSrc);
|
|
ASSERT(NULL != pDst);
|
|
ASSERT(pSrc != pDst);
|
|
ASSERT(AllocationLimit <= UNICODE_STRING_MAX_WCHAR_LEN);
|
|
|
|
// Ensure that pDst is properly initialized
|
|
RtlInitEmptyUnicodeString(pDst, NULL, 0);
|
|
|
|
UlTraceVerbose(IOCTL,
|
|
("http!UlProbeAndCaptureUnicodeString: struct @ %p, "
|
|
"Length = %hu bytes (%hu) WCHARs, "
|
|
"MaxLen = %hu bytes,"
|
|
"Mode = '%c'.\n",
|
|
pSrc,
|
|
pSrc->Length,
|
|
pSrc->Length / sizeof(WCHAR),
|
|
pSrc->MaximumLength,
|
|
(RequestorMode != KernelMode) ? 'U' : 'K'
|
|
));
|
|
|
|
// Do not allocate/copy more than the limit being enforced.
|
|
// if limit is non-zero, otherwise it is not being enforced
|
|
|
|
if (0 != AllocationLimit &&
|
|
(AllocationLimit * sizeof(WCHAR)) < pSrc->Length)
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((pSrc->MaximumLength < pSrc->Length) || (pSrc->Length == 0))
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
__try
|
|
{
|
|
// Probe the user's buffer first.
|
|
|
|
UlProbeWideString(
|
|
pSrc->Buffer,
|
|
pSrc->Length,
|
|
RequestorMode
|
|
);
|
|
|
|
// Allocate a kernel buffer and capture the user's buffer.
|
|
// The ULONG cast prevents USHORT arithmetic overflow.
|
|
|
|
pKernelBuffer = (PWSTR) UL_ALLOCATE_ARRAY(
|
|
PagedPool,
|
|
WCHAR,
|
|
((ULONG) pSrc->Length + sizeof(WCHAR))
|
|
/ sizeof(WCHAR),
|
|
UL_UNICODE_STRING_POOL_TAG
|
|
);
|
|
if (pKernelBuffer == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
__leave;
|
|
}
|
|
|
|
// Copy and null-terminate the unicode string.
|
|
|
|
RtlCopyMemory(pKernelBuffer, pSrc->Buffer, pSrc->Length);
|
|
pKernelBuffer[pSrc->Length/sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
pDst->Buffer = pKernelBuffer;
|
|
pDst->Length = pSrc->Length;
|
|
pDst->MaximumLength = pDst->Length + sizeof(WCHAR);
|
|
}
|
|
__except( UL_EXCEPTION_FILTER() )
|
|
{
|
|
Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (pKernelBuffer != NULL)
|
|
{
|
|
UL_FREE_POOL(pKernelBuffer, UL_UNICODE_STRING_POOL_TAG );
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // UlProbeAndCaptureUnicodeString
|
|
|
|
|
|
|
|
// Cleans up a UNICODE_STRING initialized by UlProbeAndCaptureUnicodeString()
|
|
__inline
|
|
VOID
|
|
UlFreeCapturedUnicodeString(
|
|
IN PUNICODE_STRING pCapturedUnicodeString
|
|
)
|
|
{
|
|
ASSERT(pCapturedUnicodeString);
|
|
|
|
if (pCapturedUnicodeString->Buffer != NULL)
|
|
{
|
|
UL_FREE_POOL(
|
|
pCapturedUnicodeString->Buffer,
|
|
UL_UNICODE_STRING_POOL_TAG
|
|
);
|
|
}
|
|
|
|
RtlInitEmptyUnicodeString(pCapturedUnicodeString, NULL, 0);
|
|
}
|
|
|
|
//
|
|
// Small macro to test the sanity of an unicode string
|
|
// also tests whether it is null terminated or not.
|
|
//
|
|
|
|
#define IS_WELL_FORMED_UNICODE_STRING(pUStr) \
|
|
((pUStr) && \
|
|
(pUStr)->Buffer && \
|
|
(pUStr)->Length && \
|
|
(!((pUStr)->Length & 1)) && \
|
|
(pUStr)->Length < (pUStr)->MaximumLength && \
|
|
(!((pUStr)->MaximumLength & 1)) && \
|
|
(pUStr)->Buffer[ \
|
|
(pUStr)->Length/sizeof(WCHAR)] \
|
|
== UNICODE_NULL \
|
|
)
|
|
|
|
//
|
|
// 64-bit interlocked routines
|
|
//
|
|
|
|
#ifdef _WIN64
|
|
|
|
#define UlInterlockedIncrement64 InterlockedIncrement64
|
|
#define UlInterlockedDecrement64 InterlockedDecrement64
|
|
#define UlInterlockedAdd64 InterlockedAdd64
|
|
#define UlInterlockedExchange64 InterlockedExchange64
|
|
|
|
#else // !_WIN64
|
|
|
|
__inline
|
|
LONGLONG
|
|
UlInterlockedIncrement64 (
|
|
IN OUT PLONGLONG Addend
|
|
)
|
|
{
|
|
LONGLONG localAddend;
|
|
LONGLONG addendPlusOne;
|
|
LONGLONG originalAddend;
|
|
|
|
do {
|
|
localAddend = *((volatile LONGLONG *) Addend);
|
|
addendPlusOne = localAddend + 1;
|
|
|
|
originalAddend = InterlockedCompareExchange64( Addend,
|
|
addendPlusOne,
|
|
localAddend );
|
|
PAUSE_PROCESSOR;
|
|
} while (originalAddend != localAddend);
|
|
|
|
return addendPlusOne;
|
|
} // UlInterlockedIncrement64
|
|
|
|
__inline
|
|
LONGLONG
|
|
UlInterlockedDecrement64 (
|
|
IN OUT PLONGLONG Addend
|
|
)
|
|
{
|
|
LONGLONG localAddend;
|
|
LONGLONG addendMinusOne;
|
|
LONGLONG originalAddend;
|
|
|
|
do {
|
|
localAddend = *((volatile LONGLONG *) Addend);
|
|
addendMinusOne = localAddend - 1;
|
|
|
|
originalAddend = InterlockedCompareExchange64( Addend,
|
|
addendMinusOne,
|
|
localAddend );
|
|
PAUSE_PROCESSOR;
|
|
} while (originalAddend != localAddend);
|
|
|
|
return addendMinusOne;
|
|
} // UlInterlockedDecrement64
|
|
|
|
__inline
|
|
LONGLONG
|
|
UlInterlockedAdd64 (
|
|
IN OUT PLONGLONG Addend,
|
|
IN LONGLONG Value
|
|
)
|
|
{
|
|
LONGLONG localAddend;
|
|
LONGLONG addendPlusValue;
|
|
LONGLONG originalAddend;
|
|
|
|
do {
|
|
localAddend = *((volatile LONGLONG *) Addend);
|
|
addendPlusValue = localAddend + Value;
|
|
|
|
originalAddend = InterlockedCompareExchange64( Addend,
|
|
addendPlusValue,
|
|
localAddend );
|
|
PAUSE_PROCESSOR;
|
|
} while (originalAddend != localAddend);
|
|
|
|
return originalAddend;
|
|
} // UlInterlockedAdd64
|
|
|
|
__inline
|
|
LONGLONG
|
|
UlInterlockedExchange64 (
|
|
IN OUT PLONGLONG Addend,
|
|
IN LONGLONG newValue
|
|
)
|
|
{
|
|
LONGLONG localAddend;
|
|
LONGLONG originalAddend;
|
|
|
|
do {
|
|
|
|
localAddend = *((volatile LONGLONG *) Addend);
|
|
|
|
originalAddend = InterlockedCompareExchange64( Addend,
|
|
newValue,
|
|
localAddend );
|
|
PAUSE_PROCESSOR;
|
|
|
|
} while (originalAddend != localAddend);
|
|
|
|
return originalAddend;
|
|
} // UlInterlockedExchange64
|
|
|
|
#endif // !_WIN64
|
|
|
|
//
|
|
// Barrier support for read-mostly operations
|
|
// Note that the AMD64 and IA32 barrier relies on program ordering
|
|
// and does not generate a hardware barrier
|
|
//
|
|
|
|
#if defined(_M_IA64)
|
|
#define UL_READMOSTLY_READ_BARRIER() __mf()
|
|
#define UL_READMOSTLY_WRITE_BARRIER() __mf()
|
|
#define UL_READMOSTLY_MEMORY_BARRIER() __mf()
|
|
#elif defined(_AMD64_) || defined(_X86_)
|
|
extern VOID _ReadWriteBarrier();
|
|
extern VOID _WriteBarrier();
|
|
#pragma intrinsic(_ReadWriteBarrier)
|
|
#pragma intrinsic(_WriteBarrier)
|
|
#define UL_READMOSTLY_READ_BARRIER() _ReadWriteBarrier()
|
|
#define UL_READMOSTLY_WRITE_BARRIER() _WriteBarrier()
|
|
#define UL_READMOSTLY_MEMORY_BARRIER() _ReadWriteBarrier()
|
|
#else
|
|
#error Cannot generate memory barriers for this architecture
|
|
#endif
|
|
|
|
__inline
|
|
PVOID
|
|
UlpFixup(
|
|
IN PUCHAR pUserPtr,
|
|
IN PUCHAR pKernelPtr,
|
|
IN PUCHAR pOffsetPtr,
|
|
IN ULONG BufferLength
|
|
)
|
|
{
|
|
ASSERT( pOffsetPtr >= pKernelPtr );
|
|
ASSERT( DIFF(pOffsetPtr - pKernelPtr) <= BufferLength );
|
|
UNREFERENCED_PARAMETER(BufferLength);
|
|
|
|
return pUserPtr + DIFF(pOffsetPtr - pKernelPtr);
|
|
|
|
} // UlpFixup
|
|
|
|
#define FIXUP_PTR( Type, pUserPtr, pKernelPtr, pOffsetPtr, BufferLength ) \
|
|
(Type)UlpFixup( \
|
|
(PUCHAR)(pUserPtr), \
|
|
(PUCHAR)(pKernelPtr), \
|
|
(PUCHAR)(pOffsetPtr), \
|
|
(BufferLength) \
|
|
)
|
|
|
|
//
|
|
// Time utility to calculate the TimeZone Bias Daylight/standart
|
|
// and returns one of the following values.
|
|
// It's taken from base\client\timedate.c.
|
|
// Once this two functions are exposed in the kernel we can get rid of
|
|
// this two functions.
|
|
//
|
|
|
|
#define UL_TIME_ZONE_ID_INVALID 0xFFFFFFFF
|
|
#define UL_TIME_ZONE_ID_UNKNOWN 0
|
|
#define UL_TIME_ZONE_ID_STANDARD 1
|
|
#define UL_TIME_ZONE_ID_DAYLIGHT 2
|
|
|
|
BOOLEAN
|
|
UlpCutoverTimeToSystemTime(
|
|
PTIME_FIELDS CutoverTime,
|
|
PLARGE_INTEGER SystemTime,
|
|
PLARGE_INTEGER CurrentSystemTime
|
|
);
|
|
|
|
ULONG
|
|
UlCalcTimeZoneIdAndBias(
|
|
IN RTL_TIME_ZONE_INFORMATION *ptzi,
|
|
OUT PLONG pBias
|
|
);
|
|
|
|
BOOLEAN
|
|
UlIsLowNPPCondition( VOID );
|
|
|
|
//
|
|
// Converts from NtStatus to Win32Status
|
|
//
|
|
|
|
#define HttpNtStatusToWin32Status( Status ) \
|
|
( ( (Status) == STATUS_SUCCESS ) \
|
|
? NO_ERROR \
|
|
: RtlNtStatusToDosErrorNoTeb( Status ) )
|
|
|
|
ULONG
|
|
HttpUnicodeToUTF8Count(
|
|
IN LPCWSTR pwszIn,
|
|
IN ULONG dwInLen,
|
|
IN BOOLEAN bEncode
|
|
);
|
|
|
|
NTSTATUS
|
|
HttpUnicodeToUTF8Encode(
|
|
IN LPCWSTR pwszIn,
|
|
IN ULONG dwInLen,
|
|
OUT PUCHAR pszOut,
|
|
IN ULONG dwOutLen,
|
|
OUT ULONG *pdwOutLen,
|
|
IN BOOLEAN bEncode
|
|
);
|
|
|
|
PSTR
|
|
UlUlongToHexString(
|
|
ULONG n,
|
|
PSTR pBuffer
|
|
);
|
|
|
|
PCHAR
|
|
UxStriStr(
|
|
const char *str1,
|
|
const char *str2,
|
|
ULONG length
|
|
);
|
|
|
|
PCHAR
|
|
UxStrStr(
|
|
const char *str1,
|
|
const char *str2,
|
|
ULONG length
|
|
);
|
|
|
|
|
|
/**************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
This routine tries to convert a SECURITY_STATUS to an NTSTATUS. It calls
|
|
MapSecurityError to perform the conversion. If the conversion fails,
|
|
it returns STATUS_UNSUCCESSFUL.
|
|
|
|
This routine always returns a valid NTSTATUS.
|
|
|
|
Arguments:
|
|
|
|
SecStatus - SECURITY_STATUS to be converted into NTSTATUS.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
--**************************************************************************/
|
|
__forceinline
|
|
NTSTATUS
|
|
SecStatusToNtStatus(
|
|
SECURITY_STATUS SecStatus
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Try to convert SECURITY_STATUS to NTSTATUS. If a corresponding
|
|
// NTSTATUS is not found, then return STATUS_UNSUCCESSFUL.
|
|
//
|
|
|
|
Status = MapSecurityError(SecStatus);
|
|
|
|
//
|
|
// The following is temporarily disabled because, the tests will fail.
|
|
// Enable this when MapSecurityError is fixed.
|
|
//
|
|
|
|
#if 0
|
|
if (!NT_SUCCESS(Status) && Status == (NTSTATUS)SecStatus)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
#endif
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the number of bytes required to encode n byte
|
|
binary data in base64.
|
|
|
|
Arguments:
|
|
|
|
BinaryLength - Length of binary data (in bytes)
|
|
pBase64Length - Pointer to length of Base64 data (in bytes)
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
--**************************************************************************/
|
|
__forceinline
|
|
NTSTATUS
|
|
BinaryToBase64Length(
|
|
IN ULONG BinaryLength,
|
|
OUT PULONG pBase64Length
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Every 6 bits in binary will be encoded by 8 bits in base64.
|
|
// Hence the output is roughly 33.33% larger than input.
|
|
// First round up (BinaryLength / 3). Now. each 3 bytes
|
|
// in binary data will yield 4 bytes of base64 encoded data.
|
|
//
|
|
// N.B. The order of arithmetic operation is important.
|
|
// Actual formula of conversion is:
|
|
// Base64Length = ceil(BinaryLength/3) * 4.
|
|
//
|
|
|
|
*pBase64Length = ((BinaryLength + 2) / 3) * 4;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
// Was there an arithmetic overflow in the above computation?
|
|
if (*pBase64Length < BinaryLength)
|
|
{
|
|
Status = STATUS_INTEGER_OVERFLOW;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the number of bytes required to decode base64
|
|
encoded data of length n back to binary format.
|
|
|
|
Arguments:
|
|
|
|
Base64Length - Length of base64 data (in bytes).
|
|
pBinaryLength - Length of binary data (in bytes).
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
--**************************************************************************/
|
|
__forceinline
|
|
NTSTATUS
|
|
Base64ToBinaryLength(
|
|
IN ULONG Base64Length,
|
|
OUT PULONG pBinaryLength
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
*pBinaryLength = (Base64Length / 4) * 3;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
// Base64Length must be a multiple of 4.
|
|
if (Base64Length % 4 != 0)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**************************************************************************++
|
|
|
|
Safer version of UlInitUnicodeString, using the private function until
|
|
the Rtl one is exposed.
|
|
|
|
--**************************************************************************/
|
|
|
|
__inline
|
|
NTSTATUS
|
|
UlInitUnicodeStringEx(
|
|
OUT PUNICODE_STRING DestinationString,
|
|
IN PCWSTR SourceString OPTIONAL
|
|
)
|
|
{
|
|
if (SourceString != NULL)
|
|
{
|
|
SIZE_T Length = wcslen(SourceString);
|
|
|
|
//
|
|
// We are actually limited to 32765 characters since we want
|
|
// to store a meaningful MaximumLength also.
|
|
//
|
|
|
|
if (Length > (UNICODE_STRING_MAX_CHARS - 1))
|
|
{
|
|
return STATUS_NAME_TOO_LONG;
|
|
}
|
|
|
|
Length *= sizeof(WCHAR);
|
|
|
|
DestinationString->Length = (USHORT) Length;
|
|
DestinationString->MaximumLength = (USHORT) (Length + sizeof(WCHAR));
|
|
DestinationString->Buffer = (PWSTR) SourceString;
|
|
}
|
|
else
|
|
{
|
|
DestinationString->Length = 0;
|
|
DestinationString->MaximumLength = 0;
|
|
DestinationString->Buffer = NULL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
BinaryToBase64(
|
|
IN PUCHAR pBinaryData,
|
|
IN ULONG BinaryDataLen,
|
|
IN PUCHAR pBase64Data,
|
|
IN ULONG Base64DataLen,
|
|
OUT PULONG BytesWritten
|
|
);
|
|
|
|
NTSTATUS
|
|
Base64ToBinary(
|
|
IN PUCHAR pBase64Data,
|
|
IN ULONG Base64DataLen,
|
|
IN PUCHAR pBinaryData,
|
|
IN ULONG BinaryDataLen,
|
|
OUT PULONG BytesWritten
|
|
);
|
|
|
|
//
|
|
// A simple exclusive spinlock at passive level that doesn't raise IRQLs.
|
|
//
|
|
|
|
#define UL_EX_LOCK_FREE 0
|
|
#define UL_EX_LOCK_LOCKED 1
|
|
|
|
typedef LONG UL_EXCLUSIVE_LOCK, *PUL_EXCLUSIVE_LOCK;
|
|
|
|
__inline
|
|
VOID
|
|
UlInitializeExclusiveLock(
|
|
PUL_EXCLUSIVE_LOCK pExLock
|
|
)
|
|
{
|
|
*pExLock = UL_EX_LOCK_FREE;
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
UlAcquireExclusiveLock(
|
|
PUL_EXCLUSIVE_LOCK pExLock
|
|
)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
if (UL_EX_LOCK_FREE == *((volatile LONG *) pExLock))
|
|
{
|
|
if (UL_EX_LOCK_FREE == InterlockedCompareExchange(
|
|
pExLock,
|
|
UL_EX_LOCK_LOCKED,
|
|
UL_EX_LOCK_FREE
|
|
))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
PAUSE_PROCESSOR;
|
|
}
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
UlReleaseExclusiveLock(
|
|
PUL_EXCLUSIVE_LOCK pExLock
|
|
)
|
|
{
|
|
ASSERT( UL_EX_LOCK_LOCKED == *pExLock );
|
|
InterlockedExchange( pExLock, UL_EX_LOCK_FREE );
|
|
}
|
|
|
|
#endif // _MISC_H_
|