/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: misc.c Abstract: This module contains the miscellaneous UL routines. Author: Keith Moore (keithmo) 10-Jun-1998 Revision History: --*/ #include "precomp.h" ULONG HttpChars[256]; // // Private prototypes. // NTSTATUS UlpRestartDeviceControl( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext ); #define FIXUP_PTR( Type, pUserPtr, pKernelPtr, pOffsetPtr, BufferLength ) \ (Type) ((PUCHAR)(pUserPtr) + DIFF((PUCHAR)(pOffsetPtr) - (PUCHAR)(pKernelPtr))) #ifdef ALLOC_PRAGMA #endif // ALLOC_PRAGMA #if 0 NOT PAGEABLE -- UlULongLongToAscii #endif // // Public functions. // /***************************************************************************++ Routine Description: Converts the given ULONGLLONG to an ASCII representation and stores it in the given string. Arguments: String - Receives the ASCII representation of the ULONGLONG. Value - Supplies the ULONGLONG to convert. Return Value: PSTR - Pointer to the next character in String *after* the converted ULONGLONG. --***************************************************************************/ PSTR UlULongLongToAscii( IN PSTR String, IN ULONGLONG Value ) { PSTR p1; PSTR p2; CHAR ch; ULONG digit; // // Special case 0 to make the rest of the routine simpler. // if (Value == 0) { *String++ = '0'; } else { // // Convert the ULONG. Note that this will result in the string // being backwards in memory. // p1 = String; p2 = String; while (Value != 0) { digit = (ULONG)( Value % 10 ); Value = Value / 10; *p1++ = '0' + (CHAR)digit; } // // Reverse the string. // String = p1; p1--; while (p1 > p2) { ch = *p1; *p1 = *p2; *p2 = ch; p2++; p1--; } } *String = '\0'; return String; } // UlULongLongToAscii NTSTATUS _RtlIntegerToUnicode( IN ULONG Value, IN ULONG Base OPTIONAL, IN LONG BufferLength, OUT PWSTR String ) { PWSTR p1; PWSTR p2; WCHAR ch; ULONG digit; // // Special case 0 to make the rest of the routine simpler. // if (Value == 0) { *String++ = L'0'; } else { // // Convert the ULONG. Note that this will result in the string // being backwards in memory. // p1 = String; p2 = String; while (Value != 0) { digit = (ULONG)( Value % 10 ); Value = Value / 10; *p1++ = L'0' + (WCHAR)digit; } // // Reverse the string. // String = p1; p1--; while (p1 > p2) { ch = *p1; *p1 = *p2; *p2 = ch; p2++; p1--; } } *String = L'\0'; return STATUS_SUCCESS; } // _RtlIntegerToUnicode /***************************************************************************++ Routine Description: Converts an ansi string to an integer. fails if any non-digit characters appears in the string. fails on negative numbers, and assumes no preceding spaces. Arguments: PUCHAR pString the string to convert ULONG Base the base, must be 10 or 16 PULONG pValue the return value of the converted integer Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlAnsiToULongLong( PUCHAR pString, ULONG Base, PULONGLONG pValue ) { ULONGLONG Value; ULONGLONG NewValue; if (Base != 10 && Base != 16) RETURN(STATUS_INVALID_PARAMETER); // // No preceding space, we already skipped it // ASSERT(IS_HTTP_LWS(pString[0]) == FALSE); Value = 0; while (pString[0] != ANSI_NULL) { if ( (Base == 10 && IS_HTTP_DIGIT(pString[0]) == FALSE) || (Base == 16 && IS_HTTP_HEX(pString[0]) == FALSE) ) { // // Not valid , bad! // RETURN(STATUS_INVALID_PARAMETER); } if (Base == 16) { if (IS_HTTP_ALPHA(pString[0])) { NewValue = 16 * Value + (UPCASE_CHAR(pString[0]) - 'A' + 10); } else { NewValue = 16 * Value + (pString[0] - '0'); } } else { NewValue = 10 * Value + (pString[0] - '0'); } if (NewValue < Value) { // // Very bad... we overflew // RETURN(STATUS_SECTION_TOO_BIG); } Value = NewValue; pString += 1; } *pValue = Value; return STATUS_SUCCESS; } // UlAnsiToULongLong /***************************************************************************++ Routine Description: Converts a unicode string to an integer. fails if any non-digit characters appear in the string. fails on negative numbers, and assumes no preceding spaces. Arguments: PWCHAR pString the string to convert ULONG Base the base, must be 10 or 16 PULONG pValue the return value of the converted integer Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlUnicodeToULongLong( PWCHAR pString, ULONG Base, PULONGLONG pValue ) { ULONGLONG Value; ULONGLONG NewValue; if (Base != 10 && Base != 16) RETURN(STATUS_INVALID_PARAMETER); // // No preceding space, we already skipped it // ASSERT(pString[0] < 128 && IS_HTTP_LWS(pString[0]) == FALSE); Value = 0; while (pString[0] != UNICODE_NULL) { if ((Base == 10 && (pString[0] >= 128 || IS_HTTP_DIGIT(pString[0]) == FALSE)) || (Base == 16 && (pString[0] >= 128 || IS_HTTP_HEX(pString[0]) == FALSE))) { // // Not valid , bad! // RETURN(STATUS_INVALID_PARAMETER); } if (Base == 16) { if (IS_HTTP_ALPHA(pString[0])) { NewValue = 16 * Value + (pString[0] - L'A' + 10); } else { NewValue = 16 * Value + (pString[0] - L'0'); } } else { NewValue = 10 * Value + (pString[0] - L'0'); } if (NewValue < Value) { // // Very bad... we overflew // RETURN(STATUS_INVALID_PARAMETER); } Value = NewValue; pString += 1; } *pValue = Value; return STATUS_SUCCESS; } // UlUnicodeToULongLong // // Private routines. // /*++ Routine Description: Routine to initialize the utilitu code. Arguments: Return Value: --*/ NTSTATUS InitializeHttpUtil( VOID ) { ULONG i; // Initialize the HttpChars array appropriately. for (i = 0; i < 128; i++) { HttpChars[i] = HTTP_CHAR; } for (i = 'A'; i <= 'Z'; i++) { HttpChars[i] |= HTTP_UPCASE; } for (i = 'a'; i <= 'z'; i++) { HttpChars[i] |= HTTP_LOCASE; } for (i = '0'; i <= '9'; i++) { HttpChars[i] |= (HTTP_DIGIT | HTTP_HEX); } for (i = 0; i <= 31; i++) { HttpChars[i] |= HTTP_CTL; } HttpChars[127] |= HTTP_CTL; HttpChars[SP] |= HTTP_LWS; HttpChars[HT] |= HTTP_LWS; for (i = 'A'; i <= 'F'; i++) { HttpChars[i] |= HTTP_HEX; } for (i = 'a'; i <= 'f'; i++) { HttpChars[i] |= HTTP_HEX; } HttpChars['('] |= HTTP_SEPERATOR; HttpChars[')'] |= HTTP_SEPERATOR; HttpChars['<'] |= HTTP_SEPERATOR; HttpChars['>'] |= HTTP_SEPERATOR; HttpChars['@'] |= HTTP_SEPERATOR; HttpChars[','] |= HTTP_SEPERATOR; HttpChars[';'] |= HTTP_SEPERATOR; HttpChars[':'] |= HTTP_SEPERATOR; HttpChars['\\'] |= HTTP_SEPERATOR; HttpChars['"'] |= HTTP_SEPERATOR; HttpChars['/'] |= HTTP_SEPERATOR; HttpChars['['] |= HTTP_SEPERATOR; HttpChars[']'] |= HTTP_SEPERATOR; HttpChars['?'] |= HTTP_SEPERATOR; HttpChars['='] |= HTTP_SEPERATOR; HttpChars['{'] |= HTTP_SEPERATOR; HttpChars['}'] |= HTTP_SEPERATOR; HttpChars[SP] |= HTTP_SEPERATOR; HttpChars[HT] |= HTTP_SEPERATOR; // // URL "reserved" characters (rfc2396) // HttpChars[';'] |= URL_LEGAL; HttpChars['/'] |= URL_LEGAL; HttpChars['\\'] |= URL_LEGAL; HttpChars['?'] |= URL_LEGAL; HttpChars[':'] |= URL_LEGAL; HttpChars['@'] |= URL_LEGAL; HttpChars['&'] |= URL_LEGAL; HttpChars['='] |= URL_LEGAL; HttpChars['+'] |= URL_LEGAL; HttpChars['$'] |= URL_LEGAL; HttpChars[','] |= URL_LEGAL; // // URL escape character // HttpChars['%'] |= URL_LEGAL; // // URL "mark" characters (rfc2396) // HttpChars['-'] |= URL_LEGAL; HttpChars['_'] |= URL_LEGAL; HttpChars['.'] |= URL_LEGAL; HttpChars['!'] |= URL_LEGAL; HttpChars['~'] |= URL_LEGAL; HttpChars['*'] |= URL_LEGAL; HttpChars['\''] |= URL_LEGAL; HttpChars['('] |= URL_LEGAL; HttpChars[')'] |= URL_LEGAL; for (i = 0; i < 128; i++) { if (!IS_HTTP_SEPERATOR(i) && !IS_HTTP_CTL(i)) { HttpChars[i] |= HTTP_TOKEN; } } return STATUS_SUCCESS; } // // constants used by the date formatter // const PWSTR pDays[] = { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" }; const PWSTR pMonths[] = { L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" }; __inline VOID TwoDigitsToUnicode( PWSTR pBuffer, ULONG Number ) { pBuffer[0] = L'0' + (WCHAR)(Number / 10); pBuffer[1] = L'0' + (WCHAR)(Number % 10); } /***************************************************************************++ Routine Description: Converts the given system time to string representation containing GMT Formatted String. Arguments: pTime - System time that needs to be converted. pBuffer - pointer to string which will contain the GMT time on successful return. BufferLength - size of pszBuff in bytes Return Value: NTSTATUS History: MuraliK 3-Jan-1995 paulmcd 4-Mar-1999 copied to ul --***************************************************************************/ NTSTATUS TimeFieldsToHttpDate( IN PTIME_FIELDS pTime, OUT PWSTR pBuffer, IN ULONG BufferLength ) { NTSTATUS Status; ASSERT(pBuffer != NULL); if (BufferLength < (HTTP_DATE_COUNT + 1)*sizeof(WCHAR)) { return STATUS_BUFFER_TOO_SMALL; } // 0 1 2 // 01234567890123456789012345678 // Formats a string like: "Thu, 14 Jul 1994 15:26:05 GMT" // // // write the constants // pBuffer[3] = L','; pBuffer[4] = pBuffer[7] = pBuffer[11] = L' '; pBuffer[19] = pBuffer[22] = L':'; // // now the variants // // // 0-based Weekday // RtlCopyMemory(&(pBuffer[0]), pDays[pTime->Weekday], 3*sizeof(WCHAR)); TwoDigitsToUnicode(&(pBuffer[5]), pTime->Day); // // 1-based Month // RtlCopyMemory(&(pBuffer[8]), pMonths[pTime->Month - 1], 3*sizeof(WCHAR)); // 1-based Status = _RtlIntegerToUnicode(pTime->Year, 10, 5, &(pBuffer[12])); ASSERT(NT_SUCCESS(Status)); pBuffer[16] = L' '; TwoDigitsToUnicode(&(pBuffer[17]), pTime->Hour); TwoDigitsToUnicode(&(pBuffer[20]), pTime->Minute); TwoDigitsToUnicode(&(pBuffer[23]), pTime->Second); RtlCopyMemory(&(pBuffer[25]), L" GMT", sizeof(L" GMT")); return STATUS_SUCCESS; } // TimeFieldsToHttpDate ULONG _MultiByteToWideCharWin9x( ULONG uCodePage, ULONG dwFlags, PCSTR lpMultiByteStr, int cchMultiByte, PWSTR lpWideCharStr, int cchWideChar ) { int i; // // simply add a 0 upper byte, it's supposed to be ascii // for (i = 0; i < cchMultiByte; ++i) { if (lpMultiByteStr[i] > 128) { lpWideCharStr[i] = (WCHAR)('_'); // (WCHAR)(DefaultChar); } else { lpWideCharStr[i] = (WCHAR)(lpMultiByteStr[i]); } } return (ULONG)(i); } // _MultiByteToWideCharWin9x /****************************************************************************** Routine Description: Copy an HTTP request to a buffer. Arguments: pRequest - Pointer to this request. pBuffer - Pointer to buffer where we'll copy. BufferLength - Length of pBuffer. pEntityBody - Pointer to entity body of request. EntityBodyLength - Length of entity body. Return Value: ******************************************************************************/ NTSTATUS UlpHttpRequestToBufferWin9x( PUL_INTERNAL_REQUEST pRequest, PUCHAR pKernelBuffer, ULONG BufferLength, PUCHAR pEntityBody, ULONG EntityBodyLength, ULONG ulLocalIPAddress, USHORT ulLocalPort, ULONG ulRemoteIPAddress, USHORT ulRemotePort ) { PHTTP_REQUEST pHttpRequest; PHTTP_UNKNOWN_HEADER pUserCurrentUnknownHeader; PUCHAR pCurrentBufferPtr; ULONG i; ULONG BytesCopied; ULONG HeaderCount = 0; PVOID pUserBuffer; PHTTP_NETWORK_ADDRESS_IPV4 pLocalAddress; PHTTP_NETWORK_ADDRESS_IPV4 pRemoteAddress; // // Sanity check. // PAGED_CODE(); ASSERT(IS_VALID_HTTP_REQUEST(pRequest)); ASSERT(pKernelBuffer != NULL); ASSERT(BufferLength > sizeof(HTTP_REQUEST)); // BUGBUG - this is used for the pointer fixups // don't know what you want to set this to // MAUROOT - NULL should be ok. pUserBuffer = NULL; // // wipe it clean // RtlZeroMemory( pKernelBuffer, sizeof(HTTP_REQUEST) ); // // Set up our pointers to the HTTP_REQUEST structure, the // header arrays we're going to fill in, and the pointer to // where we're going to start filling them in. // // CODEWORK: Make this transport independent. // pHttpRequest = (PHTTP_REQUEST)pKernelBuffer; pLocalAddress = (PHTTP_NETWORK_ADDRESS_IPV4)( pHttpRequest + 1 ); pRemoteAddress = pLocalAddress + 1; pUserCurrentUnknownHeader = (PHTTP_UNKNOWN_HEADER)( pRemoteAddress + 1 ); pCurrentBufferPtr = (PUCHAR)(pUserCurrentUnknownHeader + pRequest->UnknownHeaderCount); // // Now fill in the HTTP request structure. // pHttpRequest->ConnectionId = pRequest->ConnectionId; pHttpRequest->RequestId = pRequest->RequestId; // BUGBUG - Don't know where you'll come up with this // pHttpRequest->UrlContext = pRequest->pConfigGroup->UrlContext; // MAUROOT - NULL should be ok. pHttpRequest->UrlContext = 0; pHttpRequest->Version = pRequest->Version; pHttpRequest->Verb = pRequest->Verb; pHttpRequest->Reason = pRequest->Reason; pHttpRequest->Address.RemoteAddressLength = sizeof(HTTP_NETWORK_ADDRESS_IPV4); pHttpRequest->Address.RemoteAddressType = HTTP_NETWORK_ADDRESS_TYPE_IPV4; pHttpRequest->Address.pRemoteAddress = FIXUP_PTR( PVOID, pUserBuffer, pKernelBuffer, pRemoteAddress, BufferLength ); pRemoteAddress->IpAddress = SWAP_LONG( ulRemoteIPAddress ); pRemoteAddress->Port = SWAP_SHORT( ulRemotePort ); pHttpRequest->Address.LocalAddressLength = sizeof(HTTP_NETWORK_ADDRESS_IPV4); pHttpRequest->Address.LocalAddressType = HTTP_NETWORK_ADDRESS_TYPE_IPV4; pHttpRequest->Address.pLocalAddress = FIXUP_PTR( PVOID, pUserBuffer, pKernelBuffer, pLocalAddress, BufferLength ); pLocalAddress->IpAddress = SWAP_LONG( ulLocalIPAddress ); pLocalAddress->Port = SWAP_SHORT( ulLocalPort ); // // any raw verb? // if (pRequest->Verb == HttpVerbUnknown) { // // Need to copy in the raw verb for the client. // ASSERT(pRequest->RawVerbLength <= 0x7fff); pHttpRequest->UnknownVerbLength = (USHORT)(pRequest->RawVerbLength * sizeof(CHAR)); pHttpRequest->pUnknownVerb = FIXUP_PTR( PSTR, pUserBuffer, pKernelBuffer, pCurrentBufferPtr, BufferLength ); RtlCopyMemory( pCurrentBufferPtr, pRequest->pRawVerb, pRequest->RawVerbLength ); pCurrentBufferPtr += pRequest->RawVerbLength; // // terminate it // ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL; pCurrentBufferPtr += sizeof(CHAR); } // // copy the raw url // ASSERT(pRequest->RawUrl.Length <= 0x7fff); pHttpRequest->RawUrlLength = (USHORT)(pRequest->RawUrl.Length * sizeof(CHAR)); pHttpRequest->pRawUrl = FIXUP_PTR( PSTR, pUserBuffer, pKernelBuffer, pCurrentBufferPtr, BufferLength ); RtlCopyMemory( pCurrentBufferPtr, pRequest->RawUrl.pUrl, pRequest->RawUrl.Length ); pCurrentBufferPtr += pRequest->RawUrl.Length; // // terminate it // ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL; pCurrentBufferPtr += sizeof(CHAR); // // and now the cooked url sections // // // make sure they are valid // ASSERT(pRequest->CookedUrl.pUrl != NULL); ASSERT(pRequest->CookedUrl.pHost != NULL); ASSERT(pRequest->CookedUrl.pAbsPath != NULL); // // do the full url // ASSERT(pRequest->CookedUrl.Length <= 0xffff); pHttpRequest->CookedUrl.FullUrlLength = (USHORT)(pRequest->CookedUrl.Length); pHttpRequest->CookedUrl.pFullUrl = FIXUP_PTR( PWSTR, pUserBuffer, pKernelBuffer, pCurrentBufferPtr, BufferLength ); // // and the host // pHttpRequest->CookedUrl.HostLength = DIFF(pRequest->CookedUrl.pAbsPath - pRequest->CookedUrl.pHost) * sizeof(WCHAR); pHttpRequest->CookedUrl.pHost = pHttpRequest->CookedUrl.pFullUrl + DIFF(pRequest->CookedUrl.pHost - pRequest->CookedUrl.pUrl); // // is there a query string? // if (pRequest->CookedUrl.pQueryString != NULL) { pHttpRequest->CookedUrl.AbsPathLength = DIFF(pRequest->CookedUrl.pQueryString - pRequest->CookedUrl.pAbsPath) * sizeof(WCHAR); pHttpRequest->CookedUrl.pAbsPath = pHttpRequest->CookedUrl.pHost + (pHttpRequest->CookedUrl.HostLength / sizeof(WCHAR)); pHttpRequest->CookedUrl.QueryStringLength = (USHORT)(pRequest->CookedUrl.Length) - ( DIFF( pRequest->CookedUrl.pQueryString - pRequest->CookedUrl.pUrl ) * sizeof(WCHAR) ); pHttpRequest->CookedUrl.pQueryString = pHttpRequest->CookedUrl.pAbsPath + (pHttpRequest->CookedUrl.AbsPathLength / sizeof(WCHAR)); } else { pHttpRequest->CookedUrl.AbsPathLength = (USHORT)(pRequest->CookedUrl.Length) - ( DIFF( pRequest->CookedUrl.pAbsPath - pRequest->CookedUrl.pUrl ) * sizeof(WCHAR) ); pHttpRequest->CookedUrl.pAbsPath = pHttpRequest->CookedUrl.pHost + (pHttpRequest->CookedUrl.HostLength / sizeof(WCHAR)); pHttpRequest->CookedUrl.QueryStringLength = 0; pHttpRequest->CookedUrl.pQueryString = NULL; } // // copy the full url // RtlCopyMemory( pCurrentBufferPtr, pRequest->CookedUrl.pUrl, pRequest->CookedUrl.Length ); pCurrentBufferPtr += pRequest->CookedUrl.Length; // // terminate it // ((PWSTR)pCurrentBufferPtr)[0] = UNICODE_NULL; pCurrentBufferPtr += sizeof(WCHAR); // // no entity body, CODEWORK. // if (pRequest->ContentLength > 0 || pRequest->Chunked == 1) { pHttpRequest->MoreEntityBodyExists = 1; } else { pHttpRequest->MoreEntityBodyExists = 0; } pHttpRequest->EntityChunkCount = 0; pHttpRequest->pEntityChunks = NULL; // // Copy in the known headers. // // Loop through the known header array in the HTTP connection, // and copy any that we have. // for (i = 0; i < HttpHeaderRequestMaximum; i++) { if (pRequest->Headers[i].Valid == 1) { // // Have a header here we need to copy in. // ASSERT(pRequest->Headers[i].HeaderLength <= 0x7fff); // // ok for HeaderLength to be 0 . we will give usermode a pointer // pointing to a NULL string. RawValueLength will be 0. // pHttpRequest->Headers.pKnownHeaders[i].RawValueLength = (USHORT)(pRequest->Headers[i].HeaderLength * sizeof(CHAR)); pHttpRequest->Headers.pKnownHeaders[i].pRawValue = FIXUP_PTR( PSTR, pUserBuffer, pKernelBuffer, pCurrentBufferPtr, BufferLength ); RtlCopyMemory( pCurrentBufferPtr, pRequest->Headers[i].pHeader, pRequest->Headers[i].HeaderLength ); pCurrentBufferPtr += pRequest->Headers[i].HeaderLength; // // terminate it // ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL; pCurrentBufferPtr += sizeof(CHAR); } else { pHttpRequest->Headers.pKnownHeaders[i].RawValueLength = 0; pHttpRequest->Headers.pKnownHeaders[i].pRawValue = NULL; } } // // Now loop through the unknown headers, and copy them in. // pHttpRequest->Headers.UnknownHeaderCount = pRequest->UnknownHeaderCount; if (pRequest->UnknownHeaderCount == 0) { pHttpRequest->Headers.pUnknownHeaders = NULL; } else { pHttpRequest->Headers.pUnknownHeaders = FIXUP_PTR( PHTTP_UNKNOWN_HEADER, pUserBuffer, pKernelBuffer, pUserCurrentUnknownHeader, BufferLength ); } while (!IsListEmpty(&pRequest->UnknownHeaderList)) { PUL_HTTP_UNKNOWN_HEADER pUnknownHeader; PLIST_ENTRY pListEntry; pListEntry = RemoveHeadList(&pRequest->UnknownHeaderList); pListEntry->Flink = pListEntry->Blink = NULL; pUnknownHeader = CONTAINING_RECORD( pListEntry, UL_HTTP_UNKNOWN_HEADER, List ); HeaderCount++; ASSERT(HeaderCount <= pRequest->UnknownHeaderCount); // // First copy in the header name. // pUserCurrentUnknownHeader->NameLength = (USHORT) pUnknownHeader->HeaderNameLength * sizeof(CHAR); pUserCurrentUnknownHeader->pName = FIXUP_PTR( PSTR, pUserBuffer, pKernelBuffer, pCurrentBufferPtr, BufferLength ); RtlCopyMemory( pCurrentBufferPtr, pUnknownHeader->pHeaderName, pUnknownHeader->HeaderNameLength ); pCurrentBufferPtr += pUnknownHeader->HeaderNameLength; // // terminate it // ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL; pCurrentBufferPtr += sizeof(CHAR); // // Now copy in the header value. // ASSERT(pUnknownHeader->HeaderValue.HeaderLength <= 0x7fff); if (pUnknownHeader->HeaderValue.HeaderLength == 0) { pUserCurrentUnknownHeader->RawValueLength = 0; pUserCurrentUnknownHeader->pRawValue = NULL; } else { pUserCurrentUnknownHeader->RawValueLength = (USHORT)(pUnknownHeader->HeaderValue.HeaderLength * sizeof(CHAR)); pUserCurrentUnknownHeader->pRawValue = FIXUP_PTR( PSTR, pUserBuffer, pKernelBuffer, pCurrentBufferPtr, BufferLength ); RtlCopyMemory( pCurrentBufferPtr, pUnknownHeader->HeaderValue.pHeader, pUnknownHeader->HeaderValue.HeaderLength ); pCurrentBufferPtr += pUnknownHeader->HeaderValue.HeaderLength; // // terminate it // ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL; pCurrentBufferPtr += sizeof(CHAR); } // // skip to the next header // pUserCurrentUnknownHeader++; // // Free the unknown header structure now, as well as the pointer // (if needed). // if (pUnknownHeader->HeaderValue.OurBuffer == 1) { UL_FREE_POOL( pUnknownHeader->HeaderValue.pHeader, UL_KNOWN_HEADER_POOL_TAG ); pUnknownHeader->HeaderValue.OurBuffer = 0; } UL_FREE_POOL( pUnknownHeader, UL_UNKNOWN_HEADER_POOL_TAG ); } // // no more unknown headers exist // pRequest->UnknownHeaderCount = 0; // // Make sure we didn't use too much // ASSERT(DIFF(pCurrentBufferPtr - pKernelBuffer) <= BufferLength); return STATUS_SUCCESS; }