/*++ 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_