/*++ Copyright (c) 1998-2002 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" #include "miscp.h" // // Binary <--> Base64 Conversion Tables. // DECLSPEC_ALIGN(UL_CACHE_LINE) UCHAR BinaryToBase64Table[64] = { // 0 1 2 3 4 5 6 7 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; DECLSPEC_ALIGN(UL_CACHE_LINE) UCHAR Base64ToBinaryTable[256]; const static char hexArray[] = "0123456789ABCDEF"; #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, UlOpenRegistry ) #pragma alloc_text( PAGE, UlReadLongParameter ) #pragma alloc_text( PAGE, UlReadLongLongParameter ) #pragma alloc_text( PAGE, UlReadGenericParameter ) #pragma alloc_text( PAGE, UlIssueDeviceControl ) #endif // ALLOC_PRAGMA #if 0 NOT PAGEABLE -- UlBuildDeviceControlIrp NOT PAGEABLE -- UlULongLongToAscii NOT PAGEABLE -- UlpRestartDeviceControl NOT PAGEABLE -- UlAllocateReceiveBuffer NOT PAGEABLE -- UlAllocateReceiveBufferPool NOT PAGEABLE -- UlFreeReceiveBufferPool NOT PAGEABLE -- UlAllocateIrpContextPool NOT PAGEABLE -- UlFreeIrpContextPool NOT PAGEABLE -- UlAllocateRequestBufferPool NOT PAGEABLE -- UlFreeRequestBufferPool NOT PAGEABLE -- UlAllocateInternalRequestPool NOT PAGEABLE -- UlFreeInternalRequestPool NOT PAGEABLE -- UlAllocateChunkTrackerPool NOT PAGEABLE -- UlFreeChunkTrackerPool NOT PAGEABLE -- UlAllocateFullTrackerPool NOT PAGEABLE -- UlFreeFullTrackerPool NOT PAGEABLE -- UlAllocateResponseBufferPool NOT PAGEABLE -- UlFreeResponseBufferPool NOT PAGEABLE -- UlAllocateLogFileBufferPool NOT PAGEABLE -- UlFreeLogFileBufferPool NOT PAGEABLE -- UlAllocateLogDataBufferPool NOT PAGEABLE -- UlFreeLogDataBufferPool NOT PAGEABLE -- UlAllocateErrorLogBufferPool NOT PAGEABLE -- UlFreeErrorLogBufferPool NOT PAGEABLE -- UlUlInterlockedIncrement64 NOT PAGEABLE -- UlUlInterlockedDecrement64 NOT PAGEABLE -- UlUlInterlockedAdd64 NOT PAGEABLE -- UlUlInterlockedExchange64 NOT PAGEABLE -- TwoDigitsToUnicode NOT PAGEABLE -- TimeFieldsToHttpDate NOT PAGEABLE -- AsciiToShort NOT PAGEABLE -- TwoAsciisToShort NOT PAGEABLE -- NumericToAsciiMonth NOT PAGEABLE -- StringTimeToSystemTime #endif // // Public functions. // /***************************************************************************++ Routine Description: Opens a handle to the UL's Parameters registry key. Arguments: BaseName - Supplies the name of the parent registry key containing the Parameters key. ParametersHandle - Returns a handle to the Parameters key. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlOpenRegistry( IN PUNICODE_STRING BaseName, OUT PHANDLE ParametersHandle, IN PWSTR OptionalParameterString ) { HANDLE configHandle; NTSTATUS status; PWSTR parametersString = REGISTRY_PARAMETERS; UNICODE_STRING parametersKeyName; OBJECT_ATTRIBUTES objectAttributes; // // Sanity check. // PAGED_CODE(); if (OptionalParameterString) { parametersString = OptionalParameterString; } // // Open the registry for the initial string. // InitializeObjectAttributes( &objectAttributes, // ObjectAttributes BaseName, // ObjectName OBJ_CASE_INSENSITIVE | // Attributes OBJ_KERNEL_HANDLE, NULL, // RootDirectory NULL // SecurityDescriptor ); status = ZwOpenKey( &configHandle, KEY_READ, &objectAttributes ); if (!NT_SUCCESS(status)) { return STATUS_UNSUCCESSFUL; } // // Now open the parameters key. // status = UlInitUnicodeStringEx( ¶metersKeyName, parametersString ); if ( NT_SUCCESS(status) ) { InitializeObjectAttributes( &objectAttributes, // ObjectAttributes ¶metersKeyName, // ObjectName OBJ_CASE_INSENSITIVE, // Attributes configHandle, // RootDirectory NULL // SecurityDescriptor ); status = ZwOpenKey( ParametersHandle, KEY_READ, &objectAttributes ); } ZwClose( configHandle ); return status; } // UlOpenRegistry /***************************************************************************++ Routine Description: Reads a single (LONG/ULONG) value from the registry. Arguments: ParametersHandle - Supplies an open registry handle. ValueName - Supplies the name of the value to read. DefaultValue - Supplies the default value. Return Value: LONG - The value read from the registry or the default if the registry data was unavailable or incorrect. --***************************************************************************/ LONG UlReadLongParameter( IN HANDLE ParametersHandle, IN PWCHAR ValueName, IN LONG DefaultValue ) { PKEY_VALUE_PARTIAL_INFORMATION information = { 0 }; UNICODE_STRING valueKeyName; ULONG informationLength; LONG returnValue; NTSTATUS status; UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(LONG)]; // // Sanity check. // PAGED_CODE(); // // Build the value name, read it from the registry. // status = UlInitUnicodeStringEx( &valueKeyName, ValueName ); if ( NT_SUCCESS(status) ) { information = (PKEY_VALUE_PARTIAL_INFORMATION)buffer; status = ZwQueryValueKey( ParametersHandle, &valueKeyName, KeyValuePartialInformation, (PVOID)information, sizeof(buffer), &informationLength ); } // // If the read succeeded, the type is DWORD and the length is // sane, use it. Otherwise, use the default. // if (status == STATUS_SUCCESS && information->Type == REG_DWORD && information->DataLength == sizeof(returnValue)) { RtlMoveMemory( &returnValue, information->Data, sizeof(returnValue) ); } else { returnValue = DefaultValue; } return returnValue; } // UlReadLongParameter /***************************************************************************++ Routine Description: Reads a single (LONGLONG/ULONGLONG) value from the registry. Arguments: ParametersHandle - Supplies an open registry handle. ValueName - Supplies the name of the value to read. DefaultValue - Supplies the default value. Return Value: LONGLONG - The value read from the registry or the default if the registry data was unavailable or incorrect. --***************************************************************************/ LONGLONG UlReadLongLongParameter( IN HANDLE ParametersHandle, IN PWCHAR ValueName, IN LONGLONG DefaultValue ) { PKEY_VALUE_PARTIAL_INFORMATION information = { 0 }; UNICODE_STRING valueKeyName; ULONG informationLength; LONGLONG returnValue; NTSTATUS status; UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(LONGLONG)]; // // Sanity check. // PAGED_CODE(); // // Build the value name, read it from the registry. // status = UlInitUnicodeStringEx( &valueKeyName, ValueName ); if ( NT_SUCCESS(status) ) { information = (PKEY_VALUE_PARTIAL_INFORMATION)buffer; status = ZwQueryValueKey( ParametersHandle, &valueKeyName, KeyValuePartialInformation, (PVOID)information, sizeof(buffer), &informationLength ); } // // If the read succeeded, the type is DWORD and the length is // sane, use it. Otherwise, use the default. // if (status == STATUS_SUCCESS && information->Type == REG_QWORD && information->DataLength == sizeof(returnValue)) { RtlMoveMemory( &returnValue, information->Data, sizeof(returnValue) ); } else { returnValue = DefaultValue; } return returnValue; } // UlReadLongLongParameter /***************************************************************************++ Routine Description: Reads a single free-form value from the registry. Arguments: ParametersHandle - Supplies an open registry handle. ValueName - Supplies the name of the value to read. Value - Receives the value read from the registry. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlReadGenericParameter( IN HANDLE ParametersHandle, IN PWCHAR ValueName, OUT PKEY_VALUE_PARTIAL_INFORMATION * Value ) { KEY_VALUE_PARTIAL_INFORMATION partialInfo; UNICODE_STRING valueKeyName; ULONG informationLength; NTSTATUS status; PKEY_VALUE_PARTIAL_INFORMATION newValue; ULONG dataLength; // // Sanity check. // PAGED_CODE(); // // Build the value name, then perform an initial read. The read // should fail with buffer overflow, but that's OK. We just want // to get the length of the data. // status = UlInitUnicodeStringEx( &valueKeyName, ValueName ); if ( NT_ERROR(status) ) { return status; } status = ZwQueryValueKey( ParametersHandle, &valueKeyName, KeyValuePartialInformation, (PVOID)&partialInfo, sizeof(partialInfo), &informationLength ); if (NT_ERROR(status)) { return status; } // // Determine the data length. Ensure that strings and multi-sz get // properly terminated. // dataLength = partialInfo.DataLength - 1; if (partialInfo.Type == REG_SZ || partialInfo.Type == REG_EXPAND_SZ) { dataLength += 1; } if (partialInfo.Type == REG_MULTI_SZ) { dataLength += 2; } // // Allocate the buffer. // newValue = UL_ALLOCATE_STRUCT_WITH_SPACE( PagedPool, KEY_VALUE_PARTIAL_INFORMATION, dataLength, UL_REGISTRY_DATA_POOL_TAG ); if (newValue == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } // // update the actually allocated length for later use // dataLength += sizeof(KEY_VALUE_PARTIAL_INFORMATION); RtlZeroMemory( newValue, dataLength ); // // Perform the actual read. // status = ZwQueryValueKey( ParametersHandle, &valueKeyName, KeyValuePartialInformation, (PVOID)(newValue), dataLength, &informationLength ); if (NT_SUCCESS(status)) { *Value = newValue; } else { UL_FREE_POOL( newValue, UL_REGISTRY_DATA_POOL_TAG ); } return status; } // UlReadGenericParameter /***************************************************************************++ Routine Description: Builds a properly formatted device control IRP. Arguments: Irp - Supplies the IRP to format. IoControlCode - Supplies the device IO control code. InputBuffer - Supplies the input buffer. InputBufferLength - Supplies the length of InputBuffer. OutputBuffer - Supplies the output buffer. OutputBufferLength - Supplies the length of OutputBuffer. MdlAddress - Supplies a MDL to attach to the IRP. This is assumed to be a non-paged MDL. FileObject - Supplies the file object for the target driver. DeviceObject - Supplies the correct device object for the target driver. IoStatusBlock - Receives the final completion status of the request. CompletionRoutine - Supplies a pointer to a completion routine to call after the request completes. This will only be called if this routine returns STATUS_PENDING. CompletionContext - Supplies an uninterpreted context value passed to the completion routine. TargetThread - Optionally supplies a target thread for the IRP. If this value is NULL, then the current thread is used. --***************************************************************************/ VOID UlBuildDeviceControlIrp( IN OUT PIRP Irp, IN ULONG IoControlCode, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, IN PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength, IN PMDL MdlAddress, IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject, IN PIO_STATUS_BLOCK IoStatusBlock, IN PIO_COMPLETION_ROUTINE CompletionRoutine, IN PVOID CompletionContext, IN PETHREAD TargetThread OPTIONAL ) { PIO_STACK_LOCATION irpSp; // // Sanity check. // ASSERT( Irp != NULL ); ASSERT( FileObject != NULL ); ASSERT( DeviceObject != NULL ); // // Fill in the service independent parameters in the IRP. // Irp->Flags = 0; Irp->RequestorMode = KernelMode; Irp->PendingReturned = FALSE; Irp->UserIosb = IoStatusBlock; Irp->UserEvent = NULL; Irp->AssociatedIrp.SystemBuffer = InputBuffer ? InputBuffer : OutputBuffer; Irp->UserBuffer = OutputBuffer; Irp->MdlAddress = MdlAddress; Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; Irp->Tail.Overlay.Thread = TargetThread ? TargetThread : PsGetCurrentThread(); Irp->Tail.Overlay.OriginalFileObject = FileObject; Irp->Tail.Overlay.AuxiliaryBuffer = NULL; // // Put the file object pointer in the stack location. // irpSp = IoGetNextIrpStackLocation( Irp ); irpSp->FileObject = FileObject; irpSp->DeviceObject = DeviceObject; // // Fill in the service dependent parameters in the IRP stack. // irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode; irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength; irpSp->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer; irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL; irpSp->MinorFunction = 0; // // Set the completion routine appropriately. // if (CompletionRoutine == NULL) { IoSetCompletionRoutine( Irp, NULL, NULL, FALSE, FALSE, FALSE ); } else { IoSetCompletionRoutine( Irp, CompletionRoutine, CompletionContext, TRUE, TRUE, TRUE ); } } // UlBuildDeviceControlIrp /***************************************************************************++ 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; UNREFERENCED_PARAMETER(Base); UNREFERENCED_PARAMETER(BufferLength); // // 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: Synchronously issues a device control request to the TDI provider. Arguments: pTdiObject - Supplies a pointer to the TDI object. pIrpParameters - Supplies a pointer to the IRP parameters. IrpParametersLength - Supplies the length of pIrpParameters. pMdlBuffer - Optionally supplies a pointer to a buffer to be mapped into a MDL and placed in the MdlAddress field of the IRP. MdlBufferLength - Optionally supplies the length of pMdlBuffer. MinorFunction - Supplies the minor function code of the request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlIssueDeviceControl( IN PUX_TDI_OBJECT pTdiObject, IN PVOID pIrpParameters, IN ULONG IrpParametersLength, IN PVOID pMdlBuffer OPTIONAL, IN ULONG MdlBufferLength OPTIONAL, IN UCHAR MinorFunction ) { NTSTATUS status; PIRP pIrp; PIO_STACK_LOCATION pIrpSp; UL_STATUS_BLOCK ulStatus; IO_STATUS_BLOCK UserIosb; PMDL pMdl; // // Sanity check. // PAGED_CODE(); // // Initialize the event that will signal I/O completion. // UlInitializeStatusBlock( &ulStatus ); // // Set the file object event to the non-signaled state. // KeResetEvent( &pTdiObject->pFileObject->Event ); // // Allocate an IRP for the request. // pIrp = UlAllocateIrp( pTdiObject->pDeviceObject->StackSize, // StackSize FALSE // ChargeQuota ); if (pIrp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } // // Initialize the User IO_STATUS_BLOCK // UserIosb.Information = 0; UserIosb.Status = STATUS_SUCCESS; // // Establish the service independent parameters. // pIrp->Flags = IRP_SYNCHRONOUS_API; pIrp->RequestorMode = KernelMode; pIrp->PendingReturned = FALSE; pIrp->UserIosb = &UserIosb; pIrp->Tail.Overlay.Thread = PsGetCurrentThread(); pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject; // // If we have a MDL buffer, allocate a new MDL and map the // buffer into it. // if (pMdlBuffer != NULL) { pMdl = UlAllocateMdl( pMdlBuffer, // VirtualAddress MdlBufferLength, // Length FALSE, // SecondaryBuffer FALSE, // ChargeQuota pIrp // Irp ); if (pMdl == NULL) { UlFreeIrp( pIrp ); return STATUS_INSUFFICIENT_RESOURCES; } MmBuildMdlForNonPagedPool( pMdl ); } else { pIrp->MdlAddress = NULL; } // // Initialize the IRP stack location. // pIrpSp = IoGetNextIrpStackLocation( pIrp ); pIrpSp->FileObject = pTdiObject->pFileObject; pIrpSp->DeviceObject = pTdiObject->pDeviceObject; ASSERT( IrpParametersLength <= sizeof(pIrpSp->Parameters) ); RtlCopyMemory( &pIrpSp->Parameters, pIrpParameters, IrpParametersLength ); pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; pIrpSp->MinorFunction = MinorFunction; // // Reference the file object. // ObReferenceObject( pTdiObject->pFileObject ); // // Establish a completion routine to free the MDL and dereference // the FILE_OBJECT. // IoSetCompletionRoutine( pIrp, // Irp &UlpRestartDeviceControl, // CompletionRoutine &ulStatus, // Context TRUE, // InvokeOnSuccess TRUE, // InvokeOnError TRUE // InvokeOnCancel ); // // Issue the request. // status = UlCallDriver( pTdiObject->pDeviceObject, pIrp ); // // If necessary, wait for the request to complete and snag the // final completion status. // if (status == STATUS_PENDING) { UlWaitForStatusBlockEvent( &ulStatus ); status = ulStatus.IoStatus.Status; } return status; } // UlIssueDeviceControl /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_RECEIVE_BUFFER structure and initializes the structure. Arguments: IrpStackSize - Supplies the IrpStackSize. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateReceiveBuffer( IN CCHAR IrpStackSize ) { PUL_RECEIVE_BUFFER pBuffer; SIZE_T irpLength; SIZE_T mdlLength; SIZE_T ExtraLength; // // Calculate the required length of the buffer & allocate it. // irpLength = IoSizeOfIrp( IrpStackSize ); irpLength = ALIGN_UP( irpLength, PVOID ); mdlLength = MmSizeOfMdl( (PVOID)(PAGE_SIZE - 1), g_UlReceiveBufferSize ); mdlLength = ALIGN_UP( mdlLength, PVOID ); ExtraLength = irpLength + (mdlLength*2) + g_UlReceiveBufferSize; ASSERT( ( ExtraLength & (sizeof(PVOID) - 1) ) == 0 ); pBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE( NonPagedPool, UL_RECEIVE_BUFFER, ExtraLength, UL_RCV_BUFFER_POOL_TAG ); if (pBuffer != NULL) { PUCHAR pRawBuffer = (PUCHAR)(pBuffer); // // Initialize the IRP, MDL, and data pointers within the buffer. // pBuffer->Signature = UL_RECEIVE_BUFFER_SIGNATURE_X; pRawBuffer += ALIGN_UP( sizeof(UL_RECEIVE_BUFFER), PVOID ); pBuffer->pIrp = (PIRP)pRawBuffer; pRawBuffer += irpLength; pBuffer->pMdl = (PMDL)pRawBuffer; pRawBuffer += mdlLength; pBuffer->pPartialMdl = (PMDL)pRawBuffer; pRawBuffer += mdlLength; pBuffer->pDataArea = (PVOID)pRawBuffer; pBuffer->UnreadDataLength = 0; // // Initialize the IRP. // IoInitializeIrp( pBuffer->pIrp, // Irp (USHORT)irpLength, // PacketSize IrpStackSize // StackSize ); // // Initialize the primary MDL. // MmInitializeMdl( pBuffer->pMdl, // MemoryDescriptorList pBuffer->pDataArea, // BaseVa g_UlReceiveBufferSize // Length ); MmBuildMdlForNonPagedPool( pBuffer->pMdl ); } return (PVOID)pBuffer; } // UlAllocateReceiveBuffer /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_RECEIVE_BUFFER structure and initializes the structure. Arguments: PoolType - Supplies the type of pool to allocate. This must always be NonPagedPool. ByteLength - Supplies the byte length for the allocation request. This should be sizeof(UL_RECEIVE_BUFFER), but is basically ignored. Tag - Supplies the tag to use for the pool. This should be UL_RCV_BUFFER_POOL_TAG, but is basically ignored. Note: These parameters are required so that this function has a signature identical to ExAllocatePoolWithTag. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateReceiveBufferPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); UNREFERENCED_PARAMETER(Tag); // // Sanity check. // ASSERT( PoolType == NonPagedPool ); ASSERT( ByteLength == sizeof(UL_RECEIVE_BUFFER) ); ASSERT( Tag == UL_RCV_BUFFER_POOL_TAG ); return UlAllocateReceiveBuffer( DEFAULT_IRP_STACK_SIZE ); } // UlAllocateReceiveBufferPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_RECEIVE_BUFFER structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeReceiveBufferPool( IN PVOID pBuffer ) { PUL_RECEIVE_BUFFER pReceiveBuffer; pReceiveBuffer = (PUL_RECEIVE_BUFFER)pBuffer; ASSERT(pReceiveBuffer->Signature == UL_RECEIVE_BUFFER_SIGNATURE_X); UL_FREE_POOL( pReceiveBuffer, UL_RCV_BUFFER_POOL_TAG ); } // UlFreeReceiveBufferPool /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_IRP_CONTEXT structure and initializes the structure. Arguments: PoolType - Supplies the type of pool to allocate. This must always be NonPagedPool. ByteLength - Supplies the byte length for the allocation request. This should be sizeof(UL_IRP_CONTEXT), but is basically ignored. Tag - Supplies the tag to use for the pool. This should be UL_IRP_CONTEXT_POOL_TAG, but is basically ignored. Note: These parameters are required so that this function has a signature identical to ExAllocatePoolWithTag. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateIrpContextPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { PUL_IRP_CONTEXT pIrpContext; UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); UNREFERENCED_PARAMETER(Tag); // // Sanity check. // ASSERT( PoolType == NonPagedPool ); ASSERT( ByteLength == sizeof(UL_IRP_CONTEXT) ); ASSERT( Tag == UL_IRP_CONTEXT_POOL_TAG ); // // Allocate the IRP context. // pIrpContext = UL_ALLOCATE_STRUCT( NonPagedPool, UL_IRP_CONTEXT, UL_IRP_CONTEXT_POOL_TAG ); if (pIrpContext != NULL) { // // Initialize it. // pIrpContext->Signature = UL_IRP_CONTEXT_SIGNATURE_X; #if DBG pIrpContext->pCompletionRoutine = &UlDbgInvalidCompletionRoutine; #endif } return (PVOID)pIrpContext; } // UlAllocateIrpContextPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_IRP_CONTEXT structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeIrpContextPool( IN PVOID pBuffer ) { PUL_IRP_CONTEXT pIrpContext; pIrpContext = (PUL_IRP_CONTEXT)pBuffer; ASSERT(pIrpContext->Signature == UL_IRP_CONTEXT_SIGNATURE_X); UL_FREE_POOL( pIrpContext, UL_IRP_CONTEXT_POOL_TAG ); } // UlFreeIrpContextPool /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_REQUEST_BUFFER structure and initializes the structure. Arguments: PoolType - Supplies the type of pool to allocate. This must always be NonPagedPool. ByteLength - Supplies the byte length for the allocation request. This should be DEFAULT_MAX_REQUEST_BUFFER_SIZE but is basically ignored. Tag - Supplies the tag to use for the pool. This should be UL_REQUEST_BUFFER_POOL_TAG, but is basically ignored. Note: These parameters are required so that this function has a signature identical to ExAllocatePoolWithTag. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateRequestBufferPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { PUL_REQUEST_BUFFER pRequestBuffer; UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); UNREFERENCED_PARAMETER(Tag); // // Sanity check. // ASSERT( PoolType == NonPagedPool ); ASSERT( ByteLength == DEFAULT_MAX_REQUEST_BUFFER_SIZE ); ASSERT( Tag == UL_REQUEST_BUFFER_POOL_TAG ); // // Allocate the request buffer. // pRequestBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE( NonPagedPool, UL_REQUEST_BUFFER, DEFAULT_MAX_REQUEST_BUFFER_SIZE, UL_REQUEST_BUFFER_POOL_TAG ); if (pRequestBuffer != NULL) { // // Initialize it. // pRequestBuffer->Signature = MAKE_FREE_TAG(UL_REQUEST_BUFFER_POOL_TAG); } return (PVOID)pRequestBuffer; } // UlAllocateRequestBufferPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_REQUEST_BUFFER structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeRequestBufferPool( IN PVOID pBuffer ) { PUL_REQUEST_BUFFER pRequestBuffer; pRequestBuffer = (PUL_REQUEST_BUFFER)pBuffer; ASSERT(pRequestBuffer->Signature == MAKE_FREE_TAG(UL_REQUEST_BUFFER_POOL_TAG)); UL_FREE_POOL_WITH_SIG(pRequestBuffer, UL_REQUEST_BUFFER_POOL_TAG); } // UlFreeRequestBufferPool /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_INTERNAL_REQUEST structure and initializes the structure. Arguments: PoolType - Supplies the type of pool to allocate. This must always be NonPagedPool. ByteLength - Supplies the byte length for the allocation request. This should be sizeof(UL_INTERNAL_REQUEST) but is basically ignored. Tag - Supplies the tag to use for the pool. This should be UL_INTERNAL_REQUEST_POOL_TAG, but is basically ignored. Note: These parameters are required so that this function has a signature identical to ExAllocatePoolWithTag. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateInternalRequestPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { PUL_INTERNAL_REQUEST pRequest; PUL_FULL_TRACKER pTracker; ULONG SpaceLength; ULONG UrlBufferSize; UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); UNREFERENCED_PARAMETER(Tag); // // Sanity check. // ASSERT( PoolType == NonPagedPool ); ASSERT( ByteLength == sizeof(UL_INTERNAL_REQUEST) ); ASSERT( Tag == UL_INTERNAL_REQUEST_POOL_TAG ); // // Allocate the request buffer plus the default cooked URL buffer and // the full tracker plus the auxiliary buffer. // ASSERT( (g_UlMaxInternalUrlLength & (sizeof(WCHAR) - 1)) == 0); UrlBufferSize = g_UlMaxInternalUrlLength + sizeof(WCHAR); SpaceLength = g_UlFullTrackerSize + UrlBufferSize + DEFAULT_MAX_ROUTING_TOKEN_LENGTH; pRequest = UL_ALLOCATE_STRUCT_WITH_SPACE( NonPagedPool, UL_INTERNAL_REQUEST, SpaceLength, UL_INTERNAL_REQUEST_POOL_TAG ); if (pRequest != NULL) { pRequest->pTracker = (PUL_FULL_TRACKER)((PCHAR)pRequest + ALIGN_UP(sizeof(UL_INTERNAL_REQUEST), PVOID)); pRequest->pUrlBuffer = (PWSTR)((PCHAR)pRequest->pTracker + g_UlFullTrackerSize); pRequest->pDefaultRoutingTokenBuffer = (PWSTR)((PCHAR)pRequest->pUrlBuffer + UrlBufferSize); // // Initialize the Request structure // INIT_HTTP_REQUEST( pRequest ); pRequest->Signature = MAKE_FREE_TAG(UL_INTERNAL_REQUEST_POOL_TAG); // // Initialize the fast/cache tracker. // pTracker = pRequest->pTracker; pTracker->Signature = UL_FULL_TRACKER_POOL_TAG; pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE; pTracker->FromLookaside = FALSE; pTracker->FromRequest = TRUE; pTracker->ResponseStatusCode = 0; pTracker->AuxilaryBufferLength = g_UlMaxFixedHeaderSize + g_UlMaxVariableHeaderSize + g_UlMaxCopyThreshold; UlInitializeFullTrackerPool( pTracker, DEFAULT_MAX_IRP_STACK_SIZE ); } return (PVOID)pRequest; } // UlAllocateInternalRequestPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_INTERNAL_REQUEST structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeInternalRequestPool( IN PVOID pBuffer ) { PUL_INTERNAL_REQUEST pRequest; pRequest = (PUL_INTERNAL_REQUEST)pBuffer; ASSERT(pRequest->Signature == MAKE_FREE_TAG(UL_INTERNAL_REQUEST_POOL_TAG)); UL_FREE_POOL_WITH_SIG( pRequest, UL_INTERNAL_REQUEST_POOL_TAG ); } // UlFreeInternalRequestPool /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_CHUNK_TRACKER structure and initializes the structure. Arguments: PoolType - Supplies the type of pool to allocate. This must always be NonPagedPool. ByteLength - Supplies the byte length for the allocation request. This should be g_UlChunkTrackerSize but is basically ignored. Tag - Supplies the tag to use for the pool. This should be UL_CHUNK_TRACKER_POOL_TAG, but is basically ignored. Note: These parameters are required so that this function has a signature identical to ExAllocatePoolWithTag. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateChunkTrackerPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { PUL_CHUNK_TRACKER pTracker; UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); UNREFERENCED_PARAMETER(Tag); // // Sanity check. // ASSERT( PoolType == NonPagedPool ); ASSERT( ByteLength == g_UlChunkTrackerSize ); ASSERT( Tag == UL_CHUNK_TRACKER_POOL_TAG ); // // Allocate the tracker buffer. // pTracker = (PUL_CHUNK_TRACKER)UL_ALLOCATE_POOL( NonPagedPool, g_UlChunkTrackerSize, UL_CHUNK_TRACKER_POOL_TAG ); if (pTracker != NULL) { pTracker->Signature = MAKE_FREE_TAG(UL_CHUNK_TRACKER_POOL_TAG); pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE; pTracker->FromLookaside = TRUE; // // Set up the IRP. // pTracker->pIrp = (PIRP)((PCHAR)pTracker + ALIGN_UP(sizeof(UL_CHUNK_TRACKER), PVOID)); IoInitializeIrp( pTracker->pIrp, IoSizeOfIrp(DEFAULT_MAX_IRP_STACK_SIZE), DEFAULT_MAX_IRP_STACK_SIZE ); } return pTracker; } // UlAllocateChunkTrackerPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_CHUNK_TRACKER structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeChunkTrackerPool( IN PVOID pBuffer ) { PUL_CHUNK_TRACKER pTracker = (PUL_CHUNK_TRACKER)pBuffer; ASSERT(pTracker->Signature == MAKE_FREE_TAG(UL_CHUNK_TRACKER_POOL_TAG)); UL_FREE_POOL_WITH_SIG( pTracker, UL_CHUNK_TRACKER_POOL_TAG ); } // UlFreeChunkTrackerPool /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_FULL_TRACKER structure and initializes the structure. Arguments: PoolType - Supplies the type of pool to allocate. This must always be NonPagedPool. ByteLength - Supplies the byte length for the allocation request. This should be g_UlFullTrackerSize but is basically ignored. Tag - Supplies the tag to use for the pool. This should be UL_FULL_TRACKER_POOL_TAG, but is basically ignored. Note: These parameters are required so that this function has a signature identical to ExAllocatePoolWithTag. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateFullTrackerPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { PUL_FULL_TRACKER pTracker; UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); UNREFERENCED_PARAMETER(Tag); // // Sanity check. // ASSERT( PoolType == NonPagedPool ); ASSERT( ByteLength == g_UlFullTrackerSize ); ASSERT( Tag == UL_FULL_TRACKER_POOL_TAG ); // // Allocate the tracker buffer. // pTracker = (PUL_FULL_TRACKER)UL_ALLOCATE_POOL( NonPagedPool, g_UlFullTrackerSize, UL_FULL_TRACKER_POOL_TAG ); if (pTracker != NULL) { pTracker->Signature = MAKE_FREE_TAG(UL_FULL_TRACKER_POOL_TAG); pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE; pTracker->FromLookaside = TRUE; pTracker->FromRequest = FALSE; pTracker->AuxilaryBufferLength = g_UlMaxFixedHeaderSize + g_UlMaxVariableHeaderSize + g_UlMaxCopyThreshold; UlInitializeFullTrackerPool( pTracker, DEFAULT_MAX_IRP_STACK_SIZE ); } return pTracker; } // UlAllocateFullTrackerPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_FULL_TRACKER structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeFullTrackerPool( IN PVOID pBuffer ) { PUL_FULL_TRACKER pTracker = (PUL_FULL_TRACKER)pBuffer; ASSERT(pTracker->Signature == MAKE_FREE_TAG(UL_FULL_TRACKER_POOL_TAG)); UL_FREE_POOL_WITH_SIG( pTracker, UL_FULL_TRACKER_POOL_TAG ); } // UlFreeFullTrackerPool /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_INTERNAL_RESPONSE structure and initializes the structure. Arguments: PoolType - Supplies the type of pool to allocate. This must always be NonPagedPool. ByteLength - Supplies the byte length for the allocation request. This should be g_UlResponseBufferSize but is basically ignored. Tag - Supplies the tag to use for the pool. This should be UL_INTERNAL_RESPONSE_POOL_TAG, but is basically ignored. Note: These parameters are required so that this function has a signature identical to ExAllocatePoolWithTag. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateResponseBufferPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { PUL_INTERNAL_RESPONSE pResponseBuffer; UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); UNREFERENCED_PARAMETER(Tag); // // Sanity check. // ASSERT( PoolType == NonPagedPool ); ASSERT( ByteLength == g_UlResponseBufferSize ); ASSERT( Tag == UL_INTERNAL_RESPONSE_POOL_TAG ); // // Allocate the default internal response buffer. // pResponseBuffer = (PUL_INTERNAL_RESPONSE)UL_ALLOCATE_POOL( NonPagedPool, g_UlResponseBufferSize, UL_INTERNAL_RESPONSE_POOL_TAG ); if (pResponseBuffer != NULL) { // // Initialize it. // pResponseBuffer->Signature = MAKE_FREE_TAG(UL_INTERNAL_RESPONSE_POOL_TAG); } return (PVOID)pResponseBuffer; } // UlAllocateResponseBufferPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_INTERNAL_RESPONSE structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeResponseBufferPool( IN PVOID pBuffer ) { PUL_INTERNAL_RESPONSE pResponseBuffer; pResponseBuffer = (PUL_INTERNAL_RESPONSE)pBuffer; UL_FREE_POOL_WITH_SIG( pResponseBuffer, UL_INTERNAL_RESPONSE_POOL_TAG ); } // UlFreeResponseBufferPool /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_FILE_LOG_BUFFER structure and initializes the structure. Arguments: PoolType - Supplies the type of pool to allocate. This must always be PagedPool. ByteLength - Supplies the byte length for the allocation request. This should be sizeof(UL_LOG_FILE_BUFFER) but is basically ignored. Tag - Supplies the tag to use for the pool. This should be UL_LOG_FILE_BUFFER_POOL_TAG, but is basically ignored. Note: These parameters are required so that this function has a signature identical to ExAllocatePoolWithTag. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateLogFileBufferPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { PUL_LOG_FILE_BUFFER pLogBuffer; UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); UNREFERENCED_PARAMETER(Tag); // // Sanity check. // ASSERT( PoolType == NonPagedPool ); ASSERT( ByteLength == sizeof(UL_LOG_FILE_BUFFER) ); ASSERT( Tag == UL_LOG_FILE_BUFFER_POOL_TAG ); // // Allocate the default log buffer. // pLogBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE( PagedPool, UL_LOG_FILE_BUFFER, g_UlLogBufferSize, UL_LOG_FILE_BUFFER_POOL_TAG ); if ( pLogBuffer != NULL ) { pLogBuffer->Signature = MAKE_FREE_TAG(UL_LOG_FILE_BUFFER_POOL_TAG); pLogBuffer->BufferUsed = 0; pLogBuffer->Buffer = (PUCHAR) (pLogBuffer + 1); } return pLogBuffer; } // UlAllocateLogFileBufferPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_LOG_FILE_BUFFER structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeLogFileBufferPool( IN PVOID pBuffer ) { PUL_LOG_FILE_BUFFER pLogBuffer; pLogBuffer = (PUL_LOG_FILE_BUFFER) pBuffer; ASSERT(pLogBuffer->Signature == MAKE_FREE_TAG(UL_LOG_FILE_BUFFER_POOL_TAG)); UL_FREE_POOL_WITH_SIG( pLogBuffer, UL_LOG_FILE_BUFFER_POOL_TAG ); } // UlFreeLogFileBufferPool /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_FILE_LOG_BUFFER structure and initializes the structure. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateLogDataBufferPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { PUL_LOG_DATA_BUFFER pLogDataBuffer = NULL; USHORT Size = UL_ANSI_LOG_LINE_BUFFER_SIZE; BOOLEAN Binary = FALSE; UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); // // We understand what type of buffer is asked, by looking at the tag. // ASSERT(ByteLength == (sizeof(UL_LOG_DATA_BUFFER) + UL_ANSI_LOG_LINE_BUFFER_SIZE) || ByteLength == (sizeof(UL_LOG_DATA_BUFFER) + UL_BINARY_LOG_LINE_BUFFER_SIZE) ); ASSERT(PoolType == NonPagedPool ); ASSERT(Tag == UL_BINARY_LOG_DATA_BUFFER_POOL_TAG || Tag == UL_ANSI_LOG_DATA_BUFFER_POOL_TAG ); if (Tag == UL_BINARY_LOG_DATA_BUFFER_POOL_TAG) { Binary = TRUE; Size = UL_BINARY_LOG_LINE_BUFFER_SIZE; } pLogDataBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE( NonPagedPool, UL_LOG_DATA_BUFFER, Size, Tag ); if ( pLogDataBuffer != NULL ) { pLogDataBuffer->Signature = MAKE_FREE_TAG(Tag); pLogDataBuffer->Used = 0; pLogDataBuffer->Size = Size; pLogDataBuffer->Line = (PUCHAR) (pLogDataBuffer + 1); pLogDataBuffer->Flags.Value = 0; pLogDataBuffer->Flags.IsFromLookaside = 1; if (Binary) { pLogDataBuffer->Flags.Binary = 1; } } return pLogDataBuffer; } // UlAllocateBinaryLogDataBufferPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_LOG_DATA_BUFFER structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeLogDataBufferPool( IN PVOID pBuffer ) { ULONG Tag; PUL_LOG_DATA_BUFFER pLogDataBuffer; pLogDataBuffer = (PUL_LOG_DATA_BUFFER) pBuffer; if (pLogDataBuffer->Flags.Binary) { Tag = UL_BINARY_LOG_DATA_BUFFER_POOL_TAG; } else { Tag = UL_ANSI_LOG_DATA_BUFFER_POOL_TAG; } ASSERT(pLogDataBuffer->Signature == MAKE_FREE_TAG(Tag)); UL_FREE_POOL_WITH_SIG( pLogDataBuffer, Tag ); } // UlFreeLogDataBufferPool /***************************************************************************++ Routine Description: Allocates the pool necessary for a new UL_ERROR_LOG_BUFFER structure and initializes the structure. Return Value: PVOID - Pointer to the newly allocated block if successful, FALSE otherwise. --***************************************************************************/ PVOID UlAllocateErrorLogBufferPool( IN POOL_TYPE PoolType, IN SIZE_T ByteLength, IN ULONG Tag ) { PUL_ERROR_LOG_BUFFER pErrorLogBuffer = NULL; UNREFERENCED_PARAMETER(PoolType); UNREFERENCED_PARAMETER(ByteLength); // // We understand what type of buffer is asked, by looking at the tag. // ASSERT(ByteLength == UL_ERROR_LOG_BUFFER_SIZE); ASSERT(PoolType == NonPagedPool ); ASSERT(Tag == UL_ERROR_LOG_BUFFER_POOL_TAG); pErrorLogBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE( NonPagedPool, UL_ERROR_LOG_BUFFER, UL_ERROR_LOG_BUFFER_SIZE, Tag ); if ( pErrorLogBuffer != NULL ) { pErrorLogBuffer->Signature = MAKE_FREE_TAG(Tag); pErrorLogBuffer->Used = 0; pErrorLogBuffer->pBuffer = (PUCHAR) (pErrorLogBuffer + 1); pErrorLogBuffer->IsFromLookaside = TRUE; } return pErrorLogBuffer; } // UlAllocateErrorLogBufferPool /***************************************************************************++ Routine Description: Frees the pool allocated for a UL_ERROR_LOG_BUFFER structure. Arguments: pBuffer - Supplies the buffer to free. --***************************************************************************/ VOID UlFreeErrorLogBufferPool( IN PVOID pBuffer ) { PUL_ERROR_LOG_BUFFER pErrorLogBuffer = (PUL_ERROR_LOG_BUFFER) pBuffer; ASSERT(pErrorLogBuffer->Signature == MAKE_FREE_TAG(UL_ERROR_LOG_BUFFER_POOL_TAG)); UL_FREE_POOL_WITH_SIG( pErrorLogBuffer, UL_ERROR_LOG_BUFFER_POOL_TAG ); } // UlFreeErrorLogBufferPool // // Private routines. // /***************************************************************************++ Routine Description: Completion handler for device control IRPs. Arguments: pDeviceObject - Supplies the device object for the IRP being completed. pIrp - Supplies the IRP being completed. pContext - Supplies the context associated with this request. In this case, it's a pointer to a UL_STATUS_BLOCK structure. Return Value: NTSTATUS - STATUS_SUCCESS if IO should continue processing this IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing this IRP. --***************************************************************************/ NTSTATUS UlpRestartDeviceControl( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext ) { PUL_STATUS_BLOCK pStatus; UNREFERENCED_PARAMETER(pDeviceObject); // // If we attached an MDL to the IRP, then free it here and reset // the MDL pointer to NULL. IO can't handle a nonpaged MDL in an // IRP, so we do it here. // if (pIrp->MdlAddress != NULL) { UlFreeMdl( pIrp->MdlAddress ); pIrp->MdlAddress = NULL; } // // Complete the request. // pStatus = (PUL_STATUS_BLOCK)pContext; UlSignalStatusBlock( pStatus, pIrp->IoStatus.Status, pIrp->IoStatus.Information ); // // Tell IO to continue processing this IRP. // return STATUS_SUCCESS; } // UlpRestartDeviceControl /*++ Routine Description: Routine to initialize the utilitu code. Arguments: Return Value: --*/ NTSTATUS InitializeHttpUtil( VOID ) { ULONG i; HttpCmnInitializeHttpCharsTable(g_UrlC14nConfig.EnableDbcs); // // Initialize base64 <--> binary conversion tables. // N.B. - This initialization must be done at run-time and not // compile-time. // for (i = 0; i < 256; i++) { Base64ToBinaryTable[i] = INVALID_BASE64_TO_BINARY_TABLE_ENTRY; } for (i = 0; i < 64; i++) { ASSERT(BinaryToBase64Table[i] < 256); Base64ToBinaryTable[BinaryToBase64Table[i]] = (UCHAR)i; } return STATUS_SUCCESS; } // InitializeHttpUtil // // constants used by the date formatter // const PCWSTR pDays[] = { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" }; const PCWSTR 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 ) { ASSERT(Number < 100); 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 < (DATE_HDR_LENGTH + 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 __inline SHORT AsciiToShort( PCHAR pString ) { return (SHORT)atoi(pString); } __inline SHORT TwoAsciisToShort( PCHAR pString ) { SHORT Value; SHORT Number; Number = pString[1] - '0'; if (Number <= 9) { Value = Number; Number = pString[0] - '0'; if (Number <= 9) { Value += Number * 10; return Value; } } return 0; } /***************************************************************************++ DateTime function ported from user mode W3SVC --***************************************************************************/ /************************************************************ * Data ************************************************************/ static const PSTR s_rgchMonths[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; // Custom hash table for NumericToAsciiMonth() for mapping "Apr" to 4 static const CHAR MonthIndexTable[64] = { -1,'A', 2, 12, -1, -1, -1, 8, // A to G -1, -1, -1, -1, 7, -1,'N', -1, // F to O 9, -1,'R', -1, 10, -1, 11, -1, // P to W -1, 5, -1, -1, -1, -1, -1, -1, // X to Z -1,'A', 2, 12, -1, -1, -1, 8, // a to g -1, -1, -1, -1, 7, -1,'N', -1, // f to o 9, -1,'R', -1, 10, -1, 11, -1, // p to w -1, 5, -1, -1, -1, -1, -1, -1 // x to z }; /************************************************************ * Functions ************************************************************/ /***************************************************************************++ Converts three letters of a month to numeric month Arguments: s String to convert Returns: numeric equivalent, 0 on failure. --***************************************************************************/ __inline SHORT NumericToAsciiMonth( PCHAR s ) { UCHAR monthIndex; UCHAR c; PSTR monthString; // // use the third character as the index // c = (s[2] - 0x40) & 0x3F; monthIndex = MonthIndexTable[c]; if ( monthIndex < 13 ) { goto verify; } // // ok, we need to look at the second character // if ( monthIndex == 'N' ) { // // we got an N which we need to resolve further // // // if s[1] is 'u' then Jun, if 'a' then Jan // if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) { monthIndex = 1; } else { monthIndex = 6; } } else if ( monthIndex == 'R' ) { // // if s[1] is 'a' then March, if 'p' then April // if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) { monthIndex = 3; } else { monthIndex = 4; } } else { goto error_exit; } verify: monthString = (PSTR) s_rgchMonths[monthIndex-1]; if ( (s[0] == monthString[0]) && (s[1] == monthString[1]) && (s[2] == monthString[2]) ) { return(monthIndex); } else if ( (toupper(s[0]) == monthString[0]) && (tolower(s[1]) == monthString[1]) && (tolower(s[2]) == monthString[2]) ) { return monthIndex; } error_exit: return(0); } // NumericToAsciiMonth /***************************************************************************++ Converts a string representation of a GMT time (three different varieties) to an NT representation of a file time. We handle the following variations: Sun, 06 Nov 1994 08:49:37 GMT (RFC 822 updated by RFC 1123) Sunday, 06-Nov-94 08:49:37 GMT (RFC 850) Sun Nov 6 08:49:37 1994 (ANSI C's asctime() format) Arguments: pTimeString String representation of time field TimeStringLength Length of the string representation of time field pTime Large integer containing the time in NT format Returns: TRUE on success and FALSE on failure. History: Johnl 24-Jan-1995 Modified from WWW library ericsten 30-Nov-2000 Ported from user-mode W3SVC --***************************************************************************/ BOOLEAN StringTimeToSystemTime( IN PCSTR pTimeString, IN USHORT TimeStringLength, OUT LARGE_INTEGER *pTime ) { PSTR pString; TIME_FIELDS Fields; USHORT Length; if (NULL == pTimeString) { return FALSE; } Fields.Milliseconds = 0; Length = 0; while (Length < TimeStringLength && ',' != pTimeString[Length]) { Length++; } if (Length < TimeStringLength) { // // Thursday, 10-Jun-93 01:29:59 GMT // or: Thu, 10 Jan 1993 01:29:59 GMT // Length++; pString = (PSTR) &pTimeString[Length]; while (Length < TimeStringLength && ' ' == *pString) { Length++; pString++; } if ((TimeStringLength - Length) < 18) { return FALSE; } if ('-' == *(pString + 2)) { // // First format: Thursday, 10-Jun-93 01:29:59 GMT // if ('-' == *(pString + 6) && ' ' == *(pString + 9) && ':' == *(pString + 12) && ':' == *(pString + 15)) { Fields.Day = AsciiToShort(pString); Fields.Month = NumericToAsciiMonth(pString + 3); Fields.Year = AsciiToShort(pString + 7); Fields.Hour = AsciiToShort(pString + 10); Fields.Minute = AsciiToShort(pString + 13); Fields.Second = AsciiToShort(pString + 16); } else { return FALSE; } } else { // // Second format: Thu, 10 Jan 1993 01:29:59 GMT // if ((TimeStringLength - Length) < 20) { return FALSE; } if (' ' == *(pString + 2) && ' ' == *(pString + 6) && ' ' == *(pString + 11) && ':' == *(pString + 14) && ':' == *(pString + 17)) { Fields.Day = TwoAsciisToShort(pString); Fields.Month = NumericToAsciiMonth(pString + 3); Fields.Year = TwoAsciisToShort(pString + 7) * 100 + TwoAsciisToShort(pString + 9); Fields.Hour = TwoAsciisToShort(pString + 12); Fields.Minute = TwoAsciisToShort(pString + 15); Fields.Second = TwoAsciisToShort(pString + 18); } else { return FALSE; } } } else { // // Thu Jun 9 01:29:59 1993 GMT // Length = 0; pString = (PSTR) pTimeString; while (Length < TimeStringLength && ' ' == *pString) { Length++; pString++; } if ((TimeStringLength - Length) < 24) { return FALSE; } if (' ' != *(pString + 3) || ' ' != *(pString + 7) || ' ' != *(pString + 10) || ':' != *(pString + 13) || ':' != *(pString + 16)) { return FALSE; } if (isdigit(*(pString + 8))) { Fields.Day = AsciiToShort(pString + 8); } else { if (' ' != *(pString + 8)) { return FALSE; } Fields.Day = AsciiToShort(pString + 9); } Fields.Month = NumericToAsciiMonth(pString + 4); Fields.Year = AsciiToShort(pString + 20); Fields.Hour = AsciiToShort(pString + 11); Fields.Minute = AsciiToShort(pString + 14); Fields.Second = AsciiToShort(pString + 17); } // // Adjust for dates with only two digits // if (Fields.Year < 1000) { if (Fields.Year < 50) { Fields.Year += 2000; } else { Fields.Year += 1900; } } return RtlTimeFieldsToTime(&Fields, pTime); } /***************************************************************************++ End of DateTime function ported from user mode W3SVC --***************************************************************************/ /*++ Routine Description: Search input list of ETags for one that matches our local ETag. All strings must be NULL terminated (ANSI C strings). Arguments: pLocalETag - The local ETag we're using. pETagList - The ETag list we've received from the client. bWeakCompare - Whether using Weak Comparison is ok Returns: FIND_ETAG_STATUS value: ETAG_FOUND - pLocalETag was found on the list ETAG_NOT_FOUND - pLocalETag was NOT found on the list ETAG_PARSE_ERROR - one (or more) elements on the list were invalid Author: Anil Ruia (AnilR) 3-Apr-2000 History: Eric Stenson (EricSten) 6-Dec-2000 ported from user-mode --*/ FIND_ETAG_STATUS FindInETagList( IN PUCHAR pLocalETag, IN PUCHAR pETagList, IN BOOLEAN fWeakCompare ) { ULONG QuoteCount; PUCHAR pFileETag; BOOLEAN Matched; // We'll loop through the ETag string, looking for ETag to // compare, as long as we have an ETag to look at. do { while (IS_HTTP_LWS(*pETagList)) { pETagList++; } if (!*pETagList) { // Ran out of ETag. return ETAG_NOT_FOUND; } // If this ETag is *, it's a match. if (*pETagList == '*') { return ETAG_FOUND; } // See if this ETag is weak. if (pETagList[0] == 'W' && pETagList[1] == '/') { // This is a weak validator. If we're not doing the weak // comparison, fail. if (!fWeakCompare) { return ETAG_NOT_FOUND; } // Skip over the 'W/', and any intervening whitespace. pETagList += 2; while (IS_HTTP_LWS(*pETagList)) { pETagList++; } if (!*pETagList) { // Ran out of ETag. return ETAG_PARSE_ERROR; } } if (*pETagList != '"') { // This isn't a quoted string, so fail. return ETAG_PARSE_ERROR; } // OK, right now we should be at the start of a quoted string that // we can compare against our current ETag. QuoteCount = 0; Matched = TRUE; pFileETag = pLocalETag; // Do the actual compare. We do this by scanning the current ETag, // which is a quoted string. We look for two quotation marks, the // the delimiters of the quoted string. If after we find two quotes // in the ETag everything has matched, then we've matched this ETag. // Otherwise we'll try the next one. do { UCHAR Temp; Temp = *pETagList; if (IS_HTTP_CTL(Temp)) { return ETAG_PARSE_ERROR; } if (Temp == '"') { QuoteCount++; } if (*pFileETag != Temp) { Matched = FALSE; // at this point, we can skip the current // ETag on the list. break; } pETagList++; if (*pFileETag == '\0') { break; } pFileETag++; } while (QuoteCount != 2); if (Matched) { return ETAG_FOUND; } // Otherwise, at this point we need to look at the next ETag. while (QuoteCount != 2) { if (*pETagList == '"') { QuoteCount++; } else { if (IS_HTTP_CTL(*pETagList)) { return ETAG_PARSE_ERROR; } } pETagList++; } while (IS_HTTP_LWS(*pETagList)) { pETagList++; } if (*pETagList == ',') { pETagList++; } else { return ETAG_NOT_FOUND; } } while ( *pETagList ); return ETAG_NOT_FOUND; } // FindInETagList /*++ Routine Description: Build a NULL-terminated ANSI string from the IP address Arguments: IpAddressString - String buffer to place the ANSI string (caller allocated) TdiAddress - TDI address to be converted TdiAddressType - type of address at TdiAddress Returns: Count of bytes written into IpAddressString. Not including the terminating null. --*/ USHORT HostAddressAndPortToString( OUT PUCHAR IpAddressString, IN PVOID TdiAddress, IN USHORT TdiAddressType ) { PCHAR psz = (PCHAR) IpAddressString; if (TdiAddressType == TDI_ADDRESS_TYPE_IP) { PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) TdiAddress); struct in_addr IPv4Addr = * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr; USHORT IpPortNum = SWAP_SHORT(pIPv4Address->sin_port); psz = RtlIpv4AddressToStringA(&IPv4Addr, psz); *psz++ = ':'; psz = UlStrPrintUlong(psz, IpPortNum, '\0'); } else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6) { PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) TdiAddress); struct in6_addr IPv6Addr = * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0]; USHORT IpPortNum = SWAP_SHORT(pIPv6Address->sin6_port); *psz++ = '['; psz = RtlIpv6AddressToStringA(&IPv6Addr, psz); *psz++ = ']'; *psz++ = ':'; psz = UlStrPrintUlong(psz, IpPortNum, '\0'); } else { ASSERT(! "Unexpected TdiAddressType"); *psz = '\0'; } return DIFF_USHORT(psz - (PCHAR) IpAddressString); } // HostAddressAndPortToString /****************************************************************************++ Routine Description: Build a NULL terminated UNICODE string from the IP address & port. Arguments: IpAddressStringW - String buffer to place the UNICODE string (caller allocated) TdiAddress - TDI address to be converted TdiAddressType - type of address at TdiAddress Returns: Count of bytes written into IpAddressStringW. Not including the terminating null. --****************************************************************************/ USHORT HostAddressAndPortToStringW( PWCHAR IpAddressStringW, PVOID TdiAddress, USHORT TdiAddressType ) { PWCHAR pszW = IpAddressStringW; if (TdiAddressType == TDI_ADDRESS_TYPE_IP) { PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) TdiAddress); struct in_addr IPv4Addr = * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr; USHORT IpPortNum = SWAP_SHORT(pIPv4Address->sin_port); pszW = RtlIpv4AddressToStringW(&IPv4Addr, pszW); *pszW++ = L':'; pszW = UlStrPrintUlongW(pszW, IpPortNum, 0, L'\0'); } else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6) { PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) TdiAddress); struct in6_addr IPv6Addr = * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0]; USHORT IpPortNum = SWAP_SHORT(pIPv6Address->sin6_port); *pszW++ = L'['; pszW = RtlIpv6AddressToStringW(&IPv6Addr, pszW); *pszW++ = L']'; *pszW++ = L':'; pszW = UlStrPrintUlongW(pszW, IpPortNum, 0, L'\0'); } else { ASSERT(! "Unexpected TdiAddressType"); *pszW = L'\0'; } return (DIFF_USHORT(pszW - IpAddressStringW) * sizeof(WCHAR)); } // HostAddressAndPortToString /*++ Routine Description: Build a NULL terminated UNICODE string from the IP address Arguments: IpAddressStringW - String buffer to place the UNICODE string (caller allocated) TdiAddress - TDI address to be converted TdiAddressType - type of address at TdiAddress Returns: Count of bytes written into IpAddressStringW. Not including the terminating null. --*/ USHORT HostAddressToStringW( OUT PWCHAR IpAddressStringW, IN PVOID TdiAddress, IN USHORT TdiAddressType ) { PWCHAR pszW = IpAddressStringW; if (TdiAddressType == TDI_ADDRESS_TYPE_IP) { PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) TdiAddress); struct in_addr IPv4Addr = * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr; pszW = RtlIpv4AddressToStringW(&IPv4Addr, pszW); *pszW = L'\0'; } else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6) { PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) TdiAddress); struct in6_addr IPv6Addr = * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0]; *pszW++ = L'['; pszW = RtlIpv6AddressToStringW(&IPv6Addr, pszW); *pszW++ = L']'; *pszW = L'\0'; } else { ASSERT(! "Unexpected TdiAddressType"); *pszW = L'\0'; } return (DIFF_USHORT(pszW - IpAddressStringW) * sizeof(WCHAR)); } // HostAddressToStringW /*++ Routine Description: Build a NULL terminated routing token UNICODE string from the IP address and port. e.g 1.1.1.1:80:1.1.1.1 Arguments: IpAddressStringW - String buffer to place the UNICODE string (caller allocated) TdiAddress - TDI address to be converted TdiAddressType - type of address at TdiAddress Returns: Count of bytes written into IpAddressStringW. Not including the terminating null. --*/ USHORT HostAddressAndPortToRoutingTokenW( OUT PWCHAR IpAddressStringW, IN PVOID TdiAddress, IN USHORT TdiAddressType ) { PWCHAR pszW = IpAddressStringW; // // WARNING: // Provided buffer should be at least as big as // MAX_IP_BASED_ROUTING_TOKEN_LENGTH. // if (TdiAddressType == TDI_ADDRESS_TYPE_IP) { PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) TdiAddress); struct in_addr IPv4Addr = * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr; USHORT IpPortNum = SWAP_SHORT(pIPv4Address->sin_port); pszW = RtlIpv4AddressToStringW(&IPv4Addr, pszW); *pszW++ = L':'; pszW = UlStrPrintUlongW(pszW, IpPortNum, 0, L':'); pszW = RtlIpv4AddressToStringW(&IPv4Addr, pszW); *pszW = L'\0'; } else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6) { PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) TdiAddress); struct in6_addr IPv6Addr = * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0]; USHORT IpPortNum = SWAP_SHORT(pIPv6Address->sin6_port); *pszW++ = L'['; pszW = RtlIpv6AddressToStringW(&IPv6Addr, pszW); *pszW++ = L']'; *pszW++ = L':'; pszW = UlStrPrintUlongW(pszW, IpPortNum, 0, L':'); *pszW++ = L'['; pszW = RtlIpv6AddressToStringW(&IPv6Addr, pszW); *pszW++ = L']'; *pszW = L'\0'; } else { ASSERT(! "Unexpected TdiAddressType"); *pszW = L'\0'; } return DIFF_USHORT(pszW - IpAddressStringW) * sizeof(WCHAR); } // HostAddressAndPortToRoutingTokenW /*++ Routine Description: Calculates current bias (daylight time aware) and time zone ID. Captured from base\client\datetime.c Until this two functions are exposed in the kernel we have to keep them here. Arguments: IN CONST TIME_ZONE_INFORMATION *ptzi - time zone for which to calculate bias OUT KSYSTEM_TIME *pBias - current bias Return Value: TIME_ZONE_ID_UNKNOWN - daylight saving time is not used in the current time zone. TIME_ZONE_ID_STANDARD - The system is operating in the range covered by StandardDate. TIME_ZONE_ID_DAYLIGHT - The system is operating in the range covered by DaylightDate. TIME_ZONE_ID_INVALID - The operation failed. --*/ ULONG UlCalcTimeZoneIdAndBias( IN RTL_TIME_ZONE_INFORMATION *ptzi, OUT PLONG pBias ) { LARGE_INTEGER TimeZoneBias; LARGE_INTEGER NewTimeZoneBias; LARGE_INTEGER LocalCustomBias; LARGE_INTEGER UtcStandardTime; LARGE_INTEGER UtcDaylightTime; LARGE_INTEGER StandardTime; LARGE_INTEGER DaylightTime; LARGE_INTEGER CurrentUniversalTime; ULONG CurrentTimeZoneId = UL_TIME_ZONE_ID_INVALID; NewTimeZoneBias.QuadPart = Int32x32To64(ptzi->Bias * 60, C_NS_TICKS_PER_SEC); // // Now see if we have stored cutover times // if (ptzi->StandardStart.Month && ptzi->DaylightStart.Month) { KeQuerySystemTime(&CurrentUniversalTime); // // We have timezone cutover information. Compute the // cutover dates and compute what our current bias // is // if((!UlpCutoverTimeToSystemTime( &ptzi->StandardStart, &StandardTime, &CurrentUniversalTime) ) || (!UlpCutoverTimeToSystemTime( &ptzi->DaylightStart, &DaylightTime, &CurrentUniversalTime) ) ) { return UL_TIME_ZONE_ID_INVALID; } // // Convert standard time and daylight time to utc // LocalCustomBias.QuadPart = Int32x32To64(ptzi->StandardBias*60, C_NS_TICKS_PER_SEC); TimeZoneBias.QuadPart = NewTimeZoneBias.QuadPart + LocalCustomBias.QuadPart; UtcDaylightTime.QuadPart = DaylightTime.QuadPart + TimeZoneBias.QuadPart; LocalCustomBias.QuadPart = Int32x32To64(ptzi->DaylightBias*60, C_NS_TICKS_PER_SEC); TimeZoneBias.QuadPart = NewTimeZoneBias.QuadPart + LocalCustomBias.QuadPart; UtcStandardTime.QuadPart = StandardTime.QuadPart + TimeZoneBias.QuadPart; // // If daylight < standard, then time >= daylight and // less than standard is daylight // if (UtcDaylightTime.QuadPart < UtcStandardTime.QuadPart) { // // If today is >= DaylightTime and < StandardTime, then // We are in daylight savings time // if ((CurrentUniversalTime.QuadPart >= UtcDaylightTime.QuadPart) && (CurrentUniversalTime.QuadPart < UtcStandardTime.QuadPart)) { CurrentTimeZoneId = UL_TIME_ZONE_ID_DAYLIGHT; } else { CurrentTimeZoneId = UL_TIME_ZONE_ID_STANDARD; } } else { // // If today is >= StandardTime and < DaylightTime, then // We are in standard time // if ((CurrentUniversalTime.QuadPart >= UtcStandardTime.QuadPart) && (CurrentUniversalTime.QuadPart < UtcDaylightTime.QuadPart)) { CurrentTimeZoneId = UL_TIME_ZONE_ID_STANDARD; } else { CurrentTimeZoneId = UL_TIME_ZONE_ID_DAYLIGHT; } } // Bias in minutes *pBias = ptzi->Bias + (CurrentTimeZoneId == UL_TIME_ZONE_ID_DAYLIGHT ? ptzi->DaylightBias : ptzi->StandardBias ); } else { *pBias = ptzi->Bias; CurrentTimeZoneId = UL_TIME_ZONE_ID_UNKNOWN; } return CurrentTimeZoneId; } // UlCalcTimeZoneIdAndBias BOOLEAN UlpCutoverTimeToSystemTime( PTIME_FIELDS CutoverTime, PLARGE_INTEGER SystemTime, PLARGE_INTEGER CurrentSystemTime ) { TIME_FIELDS CurrentTimeFields; // // Get the current system time // RtlTimeToTimeFields(CurrentSystemTime,&CurrentTimeFields); // // check for absolute time field. If the year is specified, // the the time is an abosulte time // if ( CutoverTime->Year ) { return FALSE; } else { TIME_FIELDS WorkingTimeField; TIME_FIELDS ScratchTimeField; LARGE_INTEGER ScratchTime; CSHORT BestWeekdayDate; CSHORT WorkingWeekdayNumber; CSHORT TargetWeekdayNumber; CSHORT TargetYear; CSHORT TargetMonth; CSHORT TargetWeekday; // range [0..6] == [Sunday..Saturday] BOOLEAN MonthMatches; // // The time is an day in the month style time // // the convention is the Day is 1-5 specifying 1st, 2nd... Last // day within the month. The day is WeekDay. // // // Compute the target month and year // TargetWeekdayNumber = CutoverTime->Day; if ( TargetWeekdayNumber > 5 || TargetWeekdayNumber == 0 ) { return FALSE; } TargetWeekday = CutoverTime->Weekday; TargetMonth = CutoverTime->Month; MonthMatches = FALSE; TargetYear = CurrentTimeFields.Year; try_next_year: BestWeekdayDate = 0; WorkingTimeField.Year = TargetYear; WorkingTimeField.Month = TargetMonth; WorkingTimeField.Day = 1; WorkingTimeField.Hour = CutoverTime->Hour; WorkingTimeField.Minute = CutoverTime->Minute; WorkingTimeField.Second = CutoverTime->Second; WorkingTimeField.Milliseconds = CutoverTime->Milliseconds; WorkingTimeField.Weekday = 0; // // Convert to time and then back to time fields so we can determine // the weekday of day 1 on the month // if ( !RtlTimeFieldsToTime(&WorkingTimeField,&ScratchTime) ) { return FALSE; } RtlTimeToTimeFields(&ScratchTime,&ScratchTimeField); // // Compute bias to target weekday // if ( ScratchTimeField.Weekday > TargetWeekday ) { WorkingTimeField.Day += (7-(ScratchTimeField.Weekday - TargetWeekday)); } else if ( ScratchTimeField.Weekday < TargetWeekday ) { WorkingTimeField.Day += (TargetWeekday - ScratchTimeField.Weekday); } // // We are now at the first weekday that matches our target weekday // BestWeekdayDate = WorkingTimeField.Day; WorkingWeekdayNumber = 1; // // Keep going one week at a time until we either pass the // target weekday, or we match exactly // while ( WorkingWeekdayNumber < TargetWeekdayNumber ) { WorkingTimeField.Day += 7; if ( !RtlTimeFieldsToTime(&WorkingTimeField,&ScratchTime) ) { break; } RtlTimeToTimeFields(&ScratchTime,&ScratchTimeField); WorkingWeekdayNumber++; BestWeekdayDate = ScratchTimeField.Day; } WorkingTimeField.Day = BestWeekdayDate; // // If the months match, and the date is less than the current // date, then be have to go to next year. // if ( !RtlTimeFieldsToTime(&WorkingTimeField,&ScratchTime) ) { return FALSE; } if ( MonthMatches ) { if ( WorkingTimeField.Day < CurrentTimeFields.Day ) { MonthMatches = FALSE; TargetYear++; goto try_next_year; } if ( WorkingTimeField.Day == CurrentTimeFields.Day ) { if (ScratchTime.QuadPart < CurrentSystemTime->QuadPart) { MonthMatches = FALSE; TargetYear++; goto try_next_year; } } } *SystemTime = ScratchTime; return TRUE; } } // UlpCutoverTimeToSystemTime /*++ Routine Description: Predicate for testing if system is close to being out of Non-Paged Pool memory Notes: The Right Thing(tm) would be to query the value of MmMaximumNonPagedPoolInBytes (%SDXROOT%\base\ntos\mm\miglobal.c). However, this value is not exposed outside of the memory manager. (from LandyW) "A crude workaround for now would be for your driver to periodically allocate a big chunk of pool and if it fails, you know you are low. If it works, then just return it." (27-Jul-2001) We check to see if there is 3MB of NPP available. To avoid frag- mentation issue, we do this in small chunks, tallying up to 3MB. Returns: TRUE - System is low on non-paged pool FALSE - System is NOT low on non-paged pool --*/ // // NOTE: (NPP_CHUNK_COUNT * NPP_CHUNK_SIZE) == 3MB // #define NPP_CHUNK_SIZE (128 * 1024) #define NPP_CHUNK_COUNT ((3 * 1024 * 1024) / NPP_CHUNK_SIZE) BOOLEAN UlIsLowNPPCondition( VOID ) { BOOLEAN bRet; PVOID aPtrs[NPP_CHUNK_COUNT]; int i; // // Optimisim is a good thing. // bRet = FALSE; RtlZeroMemory( aPtrs, sizeof(aPtrs) ); // // To avoid failing an allocation on a fragmentation issue, we // allocate multiple smaller chunks, which brings us to 3MB of // NonPagedPool. If we fail on any of the allocs, we know we're // nearly out of NPP, and are in a Low NPP Condition. // for (i = 0 ; i < NPP_CHUNK_COUNT ; i++ ) { aPtrs[i] = UL_ALLOCATE_POOL( NonPagedPool, NPP_CHUNK_SIZE, // 128K UL_AUXILIARY_BUFFER_POOL_TAG ); if ( !aPtrs[i] ) { // Alloc failed! We're in a low-NPP condition! bRet = TRUE; goto End; } } End: // // Clean up memory // for ( i = 0; i < NPP_CHUNK_COUNT; i++ ) { if ( aPtrs[i] ) { UL_FREE_POOL( aPtrs[i], UL_AUXILIARY_BUFFER_POOL_TAG ); } } return bRet; } // UlIsLowNPPCondition /***************************************************************************++ Routine Description: Generates a hex string from a ULONG. The incoming buffer must be big enough to hold "12345678" plus the nul terminator. Arguments: n - input ULONG Return Value: a pointer to the end of the string --***************************************************************************/ PSTR UlUlongToHexString( ULONG n, PSTR wszHexDword ) { const int ULONGHEXDIGITS = sizeof(ULONG) * 2; PSTR p = wszHexDword; unsigned shift = (sizeof(ULONG) * 8) - 4; ULONG mask = 0xFu << shift; int i; for (i = 0; i < ULONGHEXDIGITS; ++i, mask >>= 4, shift -= 4) { unsigned digit = (unsigned) ((n & mask) >> shift); p[i] = hexArray[digit]; } return p+i; } // UlUlongToHexString /***************************************************************************++ Routine Description: This function does what strstr does, but assumes that str1 is not NULL terminated. str2 is NULL terminated. Arguments: str1 - the input string str2 - the substring length - length of input string Return Value: offset of the substring, NULL if none found. --***************************************************************************/ char * UxStrStr( const char *str1, const char *str2, ULONG length ) { char *cp = (char *) str1; char *s1, *s2; ULONG l1; if ( !*str2 ) return((char *)str1); while (length) { l1 = length; s1 = cp; s2 = (char *) str2; while ( l1 && *s2 && !(*s1-*s2) ) l1--, s1++, s2++; if (!*s2) return(cp); cp++; length --; } return(NULL); } /***************************************************************************++ Routine Description: This function does what strstr does, but assumes that str1 is not NULL terminated. str2 is NULL terminated. Arguments: str1 - the input string str2 - the substring length - length of input string Return Value: offset of the substring, NULL if none found. --***************************************************************************/ char * UxStriStr( const char *str1, const char *str2, ULONG length1 ) { ULONG length2; length2 = (ULONG) strlen(str2); while (length1 >= length2 ) { if(_strnicmp(str1, str2, length2) == 0) return ((char *)str1); str1 ++; length1 --; } return(NULL); } /**************************************************************************++ Routine Description: This routine encodes binary data in base64 format. It does not spilt encoded base64 data across lines. Arguments: pBinaryData - Supplied pointer to binary data to encode. BinaryDataLen - Supplies length of binary data in bytes. pBase64Data - Supplies output buffer where base64 data will be written. Base64DataLen - Supplies length of output buffer in bytes. BytesWritten - Returns the number of bytes written in the output buffer. Return Value: NTSTATUS. --**************************************************************************/ NTSTATUS BinaryToBase64( IN PUCHAR pBinaryData, IN ULONG BinaryDataLen, IN PUCHAR pBase64Data, IN ULONG Base64DataLen, OUT PULONG BytesWritten ) { NTSTATUS Status; ULONG RequiredBase64Len; ULONG i; UCHAR o0, o1, o2, o3; UCHAR end24bits[3]; PUCHAR p, pOrig; // // N.B. The following macros only work with UCHAR's (because of >> operator.) // #define UPPER_6_BITS(c) (((c) & 0xfc) >> 2) #define UPPER_4_BITS(c) (((c) & 0xf0) >> 4) #define UPPER_2_BITS(c) (((c) & 0xc0) >> 6) #define LOWER_2_BITS(c) ((c) & 0x03) #define LOWER_4_BITS(c) ((c) & 0x0f) #define LOWER_6_BITS(c) ((c) & 0x3f) // Sanity Check. ASSERT(pBinaryData && BinaryDataLen); ASSERT(pBase64Data && Base64DataLen); ASSERT(BytesWritten); // Initialize output argument. *BytesWritten = 0; // // Check if the output buffer can contain base64 encoded data. // Status = BinaryToBase64Length(BinaryDataLen, &RequiredBase64Len); if (!NT_SUCCESS(Status)) { return Status; } if (RequiredBase64Len > Base64DataLen) { return STATUS_BUFFER_TOO_SMALL; } // Return the number of bytes written. *BytesWritten = RequiredBase64Len; p = pBinaryData; pOrig = pBase64Data; for (i = 0; i + 3 <= BinaryDataLen; i += 3) { // // Encode 3 bytes at indices i, i+1, i+2. // o0 = UPPER_6_BITS(p[i]); o1 = (LOWER_2_BITS(p[i]) << 4) | UPPER_4_BITS(p[i+1]); o2 = (LOWER_4_BITS(p[i+1]) << 2) | UPPER_2_BITS(p[i+2]); o3 = LOWER_6_BITS(p[i+2]); ASSERT(o0 < 64 && o1 < 64 && o2 < 64 && o3 < 64); // // Encode binary bytes and write out the base64 bytes. // *pBase64Data++ = BinaryToBase64Table[o0]; *pBase64Data++ = BinaryToBase64Table[o1]; *pBase64Data++ = BinaryToBase64Table[o2]; *pBase64Data++ = BinaryToBase64Table[o3]; } if (i < BinaryDataLen) { // // Zero pad the remaining bits to get 24 bits. // end24bits[0] = p[i]; end24bits[1] = (BinaryDataLen > i+1) ? p[i+1] : '\0'; end24bits[2] = '\0'; o0 = UPPER_6_BITS(end24bits[0]); o1 = (LOWER_2_BITS(end24bits[0]) << 4) | UPPER_4_BITS(end24bits[1]); o2 = (LOWER_4_BITS(end24bits[1]) << 2) | UPPER_2_BITS(end24bits[2]); pBase64Data[0] = BinaryToBase64Table[o0]; pBase64Data[1] = BinaryToBase64Table[o1]; pBase64Data[2] = BinaryToBase64Table[o2]; pBase64Data[3] = '='; pBase64Data[2] = (BinaryDataLen > i+1) ? pBase64Data[2] : '='; ASSERT(pBase64Data + 4 == pOrig + RequiredBase64Len); } else { ASSERT(pBase64Data == pOrig + RequiredBase64Len); } return STATUS_SUCCESS; } /**************************************************************************++ Routine Description: This routine decodes Base64 encoded data to binary format. Arguments: pBase64Data - Supplies pointer to base64 encoded data. Base64DataLen - Length of base64 data in bytes. pBinaryData - Supplies pointer to a buffer where decoded data will be written. BinaryDataLen - Supplied the length of output buffer in bytes. BytesWritten - Returns the number of bytes written in the output buffer. Return Value: NTSTATUS. --**************************************************************************/ NTSTATUS Base64ToBinary( IN PUCHAR pBase64Data, IN ULONG Base64DataLen, IN PUCHAR pBinaryData, IN ULONG BinaryDataLen, OUT PULONG BytesWritten ) { ULONG i; UCHAR b; NTSTATUS Status; ULONG RequiredBinaryLen; ULONG BitsAvail, NumBitsAvail; PUCHAR pCurr = pBinaryData; // Sanity check. ASSERT(pBase64Data && Base64DataLen); ASSERT(pBinaryData && BinaryDataLen); ASSERT(BytesWritten); // Initialize output argument. *BytesWritten = 0; // // Check if output buffer is big enough to hold the data. // Status = Base64ToBinaryLength(Base64DataLen, &RequiredBinaryLen); if (!NT_SUCCESS(Status)) { return Status; } if (RequiredBinaryLen > BinaryDataLen) { return STATUS_BUFFER_TOO_SMALL; } ASSERT(Base64DataLen % 4 == 0); BitsAvail = 0; NumBitsAvail = 0; for (i = 0; i < Base64DataLen; i ++) { // // See if base64 char is valid. All valid base64 chars are mapped // to n where 0 <= n <= 63. In adition, '=' is also a valid // base64 char. // b = Base64ToBinaryTable[pBase64Data[i]]; if (b == INVALID_BASE64_TO_BINARY_TABLE_ENTRY) { if (pBase64Data[i] != '=') { return STATUS_INVALID_PARAMETER; } // Handle '=' outside the for loop. break; } ASSERT(NumBitsAvail < 8); ASSERT(0 <= b && b <= 63); BitsAvail = (BitsAvail << 6) | b; NumBitsAvail += 6; if (NumBitsAvail >= 8) { NumBitsAvail -= 8; *pCurr++ = (UCHAR)(BitsAvail >> NumBitsAvail); } ASSERT(NumBitsAvail < 8); } if (i < Base64DataLen) { ASSERT(pBase64Data[i] == '='); // // There can be at most two '=' chars and they must appear at the end // of the encoded data. A char, if any, that follows '=' char, must // be a '='. // if (i + 2 < Base64DataLen || (i + 1 < Base64DataLen && pBase64Data[i+1] != '=')) { return STATUS_INVALID_PARAMETER; } // // All the remaining bits at this point must be zeros. // ASSERT(NumBitsAvail > 0 && NumBitsAvail < 8); if (BitsAvail & ((1<