/*++ Copyright (c) 1998-2001 Microsoft Corporation Module Name: ioctl.cxx Abstract: This module implements various IOCTL handlers. Author: Keith Moore (keithmo) 10-Jun-1998 Revision History: Paul McDaniel (paulmcd) 15-Mar-1999 Modified SendResponse --*/ #include "precomp.h" #define VALIDATE_OFFSET( off, input ) ((off) < (input)) #define VALIDATE_LENGTH( len, input ) ((len) < (input)) #define VALIDATE_OFFSET_LENGTH_PAIR( off, len, input ) \ ( VALIDATE_OFFSET( off, input ) && \ VALIDATE_LENGTH( len, input ) && \ (((off) + (len)) < (input)) ) VOID UlpRestartSendHttpResponse( IN PVOID pCompletionContext, IN NTSTATUS Status, IN ULONG_PTR Information ); #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, UlQueryControlChannelIoctl ) #pragma alloc_text( PAGE, UlSetControlChannelIoctl ) #pragma alloc_text( PAGE, UlCreateConfigGroupIoctl ) #pragma alloc_text( PAGE, UlDeleteConfigGroupIoctl ) #pragma alloc_text( PAGE, UlQueryConfigGroupIoctl ) #pragma alloc_text( PAGE, UlSetConfigGroupIoctl ) #pragma alloc_text( PAGE, UlAddUrlToConfigGroupIoctl ) #pragma alloc_text( PAGE, UlRemoveUrlFromConfigGroupIoctl ) #pragma alloc_text( PAGE, UlRemoveAllUrlsFromConfigGroupIoctl ) #pragma alloc_text( PAGE, UlConfigGroupControlIoctl ) #pragma alloc_text( PAGE, UlQueryAppPoolInformationIoctl ) #pragma alloc_text( PAGE, UlSetAppPoolInformationIoctl ) #pragma alloc_text( PAGE, UlReceiveHttpRequestIoctl ) #pragma alloc_text( PAGE, UlReceiveEntityBodyIoctl ) #pragma alloc_text( PAGE, UlSendHttpResponseIoctl ) #pragma alloc_text( PAGE, UlSendEntityBodyIoctl ) #pragma alloc_text( PAGE, UlFlushResponseCacheIoctl ) #pragma alloc_text( PAGE, UlWaitForDemandStartIoctl ) #pragma alloc_text( PAGE, UlWaitForDisconnectIoctl ) #pragma alloc_text( PAGE, UlAddTransientUrlIoctl ) #pragma alloc_text( PAGE, UlRemoveTransientUrlIoctl ) #pragma alloc_text( PAGE, UlFilterAcceptIoctl ) #pragma alloc_text( PAGE, UlFilterCloseIoctl ) #pragma alloc_text( PAGE, UlFilterRawReadIoctl ) #pragma alloc_text( PAGE, UlFilterRawWriteIoctl ) #pragma alloc_text( PAGE, UlFilterAppReadIoctl ) #pragma alloc_text( PAGE, UlFilterAppWriteIoctl ) #pragma alloc_text( PAGE, UlReceiveClientCertIoctl ) #pragma alloc_text( PAGE, UlGetCountersIoctl ) #endif // ALLOC_PRAGMA #if 0 NOT PAGEABLE -- UlpRestartSendHttpResponse #endif // // Public functions. // /***************************************************************************++ Routine Description: This routine queries information associated with a control channel. Note: This is a METHOD_OUT_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlQueryControlChannelIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_CONTROL_CHANNEL_INFO pInfo = NULL; PUL_CONTROL_CHANNEL pControlChannel; PVOID pMdlBuffer; ULONG length; PVOID pMdlVa; // // sanity check. // PAGED_CODE(); // // better be a control channel // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { // // Not a control channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } pControlChannel = GET_CONTROL_CHANNEL(pIrpSp->FileObject); if (IS_VALID_CONTROL_CHANNEL(pControlChannel) == FALSE) { Status = STATUS_INVALID_PARAMETER; goto end; } // // Ensure the input buffer looks good // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_CONTROL_CHANNEL_INFO)) { // // input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // fetch it // pInfo = (PHTTP_CONTROL_CHANNEL_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); __try { switch (pInfo->InformationClass) { case HttpControlChannelStateInformation: case HttpControlChannelBandwidthInformation: case HttpControlChannelConnectionInformation: case HttpControlChannelAutoResponseInformation: // if no outbut buffer pass down in the Irp // that means app is asking for the required // field length if (!pIrp->MdlAddress) { pMdlBuffer = NULL; } else { pMdlBuffer = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, LowPagePriority ); if (pMdlBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } // Also make sure that user buffer was good pMdlVa = MmGetMdlVirtualAddress(pIrp->MdlAddress); ProbeForWrite( pMdlVa, pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof(UCHAR) ); } Status = UlGetControlChannelInformation( pControlChannel, pInfo->InformationClass, pMdlBuffer, pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, &length ); if (!NT_SUCCESS(Status)) { __leave; } pIrp->IoStatus.Information = (ULONG_PTR)length; break; default: Status = STATUS_INVALID_PARAMETER; __leave; break; } } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } end: // // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlQueryControlChannelIoctl /***************************************************************************++ Routine Description: This routine sets information associated with a control channel. Note: This is a METHOD_IN_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlSetControlChannelIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_CONTROL_CHANNEL_INFO pInfo; PUL_CONTROL_CHANNEL pControlChannel; PVOID pMdlBuffer; // // sanity check. // PAGED_CODE(); // // better be a control channel // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { // // Not a control channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } pControlChannel = GET_CONTROL_CHANNEL(pIrpSp->FileObject); if (IS_VALID_CONTROL_CHANNEL(pControlChannel) == FALSE) { Status = STATUS_INVALID_PARAMETER; goto end; } // // Ensure the input buffer looks good // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_CONTROL_CHANNEL_INFO)) { // // input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // // Ensure the output buffer looks good // if (!pIrp->MdlAddress) { Status = STATUS_INVALID_PARAMETER; goto end; } // fetch it // pInfo = (PHTTP_CONTROL_CHANNEL_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); switch (pInfo->InformationClass) { case HttpControlChannelStateInformation: case HttpControlChannelBandwidthInformation: case HttpControlChannelConnectionInformation: case HttpControlChannelAutoResponseInformation: case HttpControlChannelFilterInformation: case HttpControlChannelTimeoutInformation: case HttpControlChannelUTF8Logging: // // call the function // pMdlBuffer = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, LowPagePriority ); if (pMdlBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { Status = UlSetControlChannelInformation( pControlChannel, pInfo->InformationClass, pMdlBuffer, pIrpSp->Parameters.DeviceIoControl.OutputBufferLength ); } if (NT_SUCCESS(Status) == FALSE) goto end; break; default: Status = STATUS_INVALID_PARAMETER; goto end; } end: // // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlSetControlChannelIoctl /***************************************************************************++ Routine Description: This routine creates a new configuration group. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlCreateConfigGroupIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_CONFIG_GROUP_INFO pInfo = NULL; // // sanity check. // PAGED_CODE(); // better be a control channel // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { // Not a control channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // Ensure the output buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HTTP_CONFIG_GROUP_INFO)) { // output buffer too small. Status = STATUS_BUFFER_TOO_SMALL; goto end; } // Fetch out the output buffer // pInfo = (PHTTP_CONFIG_GROUP_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); // it's pure output, wipe it to be sure // RtlZeroMemory(pInfo, sizeof(HTTP_CONFIG_GROUP_INFO)); // Call the internal worker func // Status = UlCreateConfigGroup( GET_CONTROL_CHANNEL(pIrpSp->FileObject), &pInfo->ConfigGroupId ); if (NT_SUCCESS(Status) == FALSE) goto end; end: // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; // how much output should we return? // pIrp->IoStatus.Information = sizeof(HTTP_CONFIG_GROUP_INFO); UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlCreateConfigGroupIoctl /***************************************************************************++ Routine Description: This routine deletes an existing configuration group. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlDeleteConfigGroupIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_CONFIG_GROUP_INFO pInfo = NULL; // // sanity check. // PAGED_CODE(); // better be a control channel // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { // Not a control channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_CONFIG_GROUP_INFO)) { // output buffer too small. Status = STATUS_BUFFER_TOO_SMALL; goto end; } // fetch out the input buffer // pInfo = (PHTTP_CONFIG_GROUP_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); // Call the internal worker func // __try { HTTP_CONFIG_GROUP_ID ConfigGroupId = pInfo->ConfigGroupId; Status = UlDeleteConfigGroup(ConfigGroupId); } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } if (NT_SUCCESS(Status) == FALSE) goto end; end: // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlDeleteConfigGroupIoctl /***************************************************************************++ Routine Description: This routine queries information associated with a configuration group. Note: This is a METHOD_OUT_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlQueryConfigGroupIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_CONFIG_GROUP_INFO pInfo = NULL; PVOID pMdlBuffer; ULONG length = 0L; // // sanity check. // PAGED_CODE(); // // Going to access the url string from user mode memory // __try { // // better be a control channel // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { // // Not a control channel. // Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } // // Ensure the input buffer looks good // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_CONFIG_GROUP_INFO)) { // // input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; __leave; } // // fetch it // pInfo = (PHTTP_CONFIG_GROUP_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); switch (pInfo->InformationClass) { #if DBG case HttpConfigGroupGetUrlInfo: { PHTTP_CONFIG_GROUP_DBG_URL_INFO pUrlInfo; PUL_URL_CONFIG_GROUP_INFO pUrlCGInfo; // check the output buffer // if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HTTP_CONFIG_GROUP_DBG_URL_INFO)) { // output buffer too small. Status = STATUS_BUFFER_TOO_SMALL; __leave; } // grab the buffer // pUrlInfo = (PHTTP_CONFIG_GROUP_DBG_URL_INFO) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority ); if (pUrlInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } pUrlCGInfo = (PUL_URL_CONFIG_GROUP_INFO)UL_ALLOCATE_POOL( NonPagedPool, sizeof(UL_URL_CONFIG_GROUP_INFO), UL_CG_URL_INFO_POOL_TAG ); if (pUrlCGInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } // grab the url // if (pUrlInfo->Url.Length == 0 || pUrlInfo->Url.MaximumLength > pUrlInfo->Url.Length || pUrlInfo->Url.Buffer == NULL) { // output buffer too small. Status = STATUS_INVALID_PARAMETER; __leave; } // good memory? // ProbeTestForRead(pUrlInfo->Url.Buffer, pUrlInfo->Url.Length + sizeof(WCHAR), sizeof(WCHAR)); // must be null terminated // if (pUrlInfo->Url.Buffer[pUrlInfo->Url.Length/sizeof(WCHAR)] != UNICODE_NULL) { Status = STATUS_INVALID_PARAMETER; __leave; } // CODEWORK: validate the incoming url. // // call the function // Status = UlGetConfigGroupInfoForUrl( pUrlInfo->Url.Buffer, NULL, // PUL_HTTP_CONNECTION pUrlCGInfo); if (NT_SUCCESS(Status) == FALSE) __leave; // copy it over // //pUrlInfo->Url; pUrlInfo->MaxBandwidth = -1; if (pUrlCGInfo->pMaxBandwidth != NULL) { pUrlInfo->MaxBandwidth = pUrlCGInfo->pMaxBandwidth->MaxBandwidth.MaxBandwidth; } pUrlInfo->MaxConnections = -1; if (pUrlCGInfo->pMaxConnections != NULL) { pUrlInfo->MaxConnections = pUrlCGInfo->pMaxConnections->MaxConnections.MaxConnections; } pUrlInfo->CurrentState = pUrlCGInfo->CurrentState; pUrlInfo->UrlContext = pUrlCGInfo->UrlContext; pUrlInfo->pReserved = pUrlCGInfo; // update the output length // pIrp->IoStatus.Information = sizeof(HTTP_CONFIG_GROUP_DBG_URL_INFO); } break; case HttpConfigGroupFreeUrlInfo: { PHTTP_CONFIG_GROUP_DBG_URL_INFO pUrlInfo; // check the output buffer // if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HTTP_CONFIG_GROUP_DBG_URL_INFO)) { // output buffer too small. Status = STATUS_BUFFER_TOO_SMALL; __leave; } // grab the buffer // pUrlInfo = (PHTTP_CONFIG_GROUP_DBG_URL_INFO) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority ); if (pUrlInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } // call the function // UlpConfigGroupInfoRelease( (PUL_URL_CONFIG_GROUP_INFO)(pUrlInfo->pReserved) ); UL_FREE_POOL( (PUL_URL_CONFIG_GROUP_INFO)(pUrlInfo->pReserved), UL_CG_URL_INFO_POOL_TAG ); // update the output length // pIrp->IoStatus.Information = 0; } break; case HttpConfigGroupUrlStaleTest: { Status = STATUS_NOT_SUPPORTED; } break; #endif // DBG case HttpConfigGroupBandwidthInformation: case HttpConfigGroupConnectionInformation: case HttpConfigGroupStateInformation: case HttpConfigGroupConnectionTimeoutInformation: // // call the function // pMdlBuffer = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, LowPagePriority ); if (pMdlBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { Status = UlQueryConfigGroupInformation( pInfo->ConfigGroupId, pInfo->InformationClass, pMdlBuffer, pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, &length ); } if (!NT_SUCCESS(Status)) { __leave; } pIrp->IoStatus.Information = (ULONG_PTR)length; break; case HttpConfigGroupAutoResponseInformation: case HttpConfigGroupAppPoolInformation: case HttpConfigGroupSecurityInformation: default: Status = STATUS_INVALID_PARAMETER; __leave; } } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } // // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlQueryConfigGroupIoctl /***************************************************************************++ Routine Description: This routine sets information associated with a configuration group. Note: This is a METHOD_IN_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlSetConfigGroupIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_CONFIG_GROUP_INFO pInfo = NULL; PVOID pMdlBuffer; PVOID pMdlVa; ULONG OutputLength; // // sanity check. // PAGED_CODE(); // // better be a control channel // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { // // Not a control channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer looks good // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_CONFIG_GROUP_INFO)) { // // input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // fetch it // pInfo = (PHTTP_CONFIG_GROUP_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); OutputLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength; switch (pInfo->InformationClass) { case HttpConfigGroupLogInformation: { __try { // if no outbut buffer pass down in the Irp // that probably means WAS is asking us to // remove the logging for this config_group // we will handle this case later...CODEWORK if (!pIrp->MdlAddress) { pMdlBuffer = NULL; } else { pMdlBuffer = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, LowPagePriority ); if (pMdlBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } // Also make sure that user buffer was good pMdlVa = MmGetMdlVirtualAddress(pIrp->MdlAddress); ProbeTestForRead( pMdlVa, OutputLength, sizeof(UCHAR) ); } UlTrace(IOCTL, ("UlSetConfigGroupIoctl: CGroupId=%I64x, " "LogInformation, pMdlBuffer=%p, length=%d\n", pInfo->ConfigGroupId, pMdlBuffer, OutputLength )); Status = UlSetConfigGroupInformation( pInfo->ConfigGroupId, pInfo->InformationClass, pMdlBuffer, OutputLength ); } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } if (NT_SUCCESS(Status) == FALSE) goto end; } break; case HttpConfigGroupAutoResponseInformation: case HttpConfigGroupAppPoolInformation: case HttpConfigGroupBandwidthInformation: case HttpConfigGroupConnectionInformation: case HttpConfigGroupStateInformation: case HttpConfigGroupSecurityInformation: case HttpConfigGroupSiteInformation: case HttpConfigGroupConnectionTimeoutInformation: // // call the function // pMdlBuffer = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, LowPagePriority ); if (pMdlBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { UlTrace(IOCTL, ("UlSetConfigGroupIoctl: CGroupId=%I64x, " "InfoClass=%d, pMdlBuffer=%p, length=%d\n", pInfo->ConfigGroupId, pInfo->InformationClass, pMdlBuffer, OutputLength )); Status = UlSetConfigGroupInformation( pInfo->ConfigGroupId, pInfo->InformationClass, pMdlBuffer, OutputLength ); } if (NT_SUCCESS(Status) == FALSE) goto end; break; default: Status = STATUS_INVALID_PARAMETER; goto end; break; } end: // // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlSetConfigGroupIoctl /***************************************************************************++ Routine Description: This routine adds a new URL prefix to a configuration group. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlAddUrlToConfigGroupIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_CONFIG_GROUP_URL_INFO pInfo = NULL; // // sanity check. // PAGED_CODE(); // better be a control channel // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { // Not a control channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_CONFIG_GROUP_URL_INFO)) { // bad buffer // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // Fetch out the input buffer // pInfo = (PHTTP_CONFIG_GROUP_URL_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); // does it look appropriate? // if (pInfo->FullyQualifiedUrl.MaximumLength < pInfo->FullyQualifiedUrl.Length || pInfo->FullyQualifiedUrl.Length == 0 || (pInfo->FullyQualifiedUrl.Length % sizeof(WCHAR)) != 0 || pInfo->FullyQualifiedUrl.Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto end; } // Going to access the url string from user mode memory // __try { // good memory? // ProbeTestForRead(pInfo->FullyQualifiedUrl.Buffer, pInfo->FullyQualifiedUrl.Length + sizeof(WCHAR), sizeof(WCHAR)); // must be null terminated // if (pInfo->FullyQualifiedUrl.Buffer[pInfo->FullyQualifiedUrl.Length/sizeof(WCHAR)] != UNICODE_NULL) { Status = STATUS_INVALID_PARAMETER; __leave; } // CODEWORK: validate the incoming url. // // Call the internal worker func // Status = UlAddUrlToConfigGroup(pInfo->ConfigGroupId, &pInfo->FullyQualifiedUrl, pInfo->UrlContext); if (NT_SUCCESS(Status) == FALSE) __leave; } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } if (NT_SUCCESS(Status) == FALSE) goto end; end: // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlAddUrlToConfigGroupIoctl /***************************************************************************++ Routine Description: This routine removes a URL prefix from a configuration group. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlRemoveUrlFromConfigGroupIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_CONFIG_GROUP_URL_INFO pInfo = NULL; // // sanity check. // PAGED_CODE(); // better be a control channel // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { // Not a control channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_CONFIG_GROUP_URL_INFO)) { // bad buffer // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // Fetch out the input buffer // pInfo = (PHTTP_CONFIG_GROUP_URL_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); // does it look appropriate? // if (pInfo->FullyQualifiedUrl.MaximumLength < pInfo->FullyQualifiedUrl.Length || pInfo->FullyQualifiedUrl.Length == 0 || (pInfo->FullyQualifiedUrl.Length % sizeof(WCHAR)) != 0 || pInfo->FullyQualifiedUrl.Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto end; } // Going to access the url string from user mode memory // __try { // good memory? // ProbeTestForRead(pInfo->FullyQualifiedUrl.Buffer, pInfo->FullyQualifiedUrl.Length + sizeof(WCHAR), sizeof(WCHAR)); // must be null terminated // if (pInfo->FullyQualifiedUrl.Buffer[pInfo->FullyQualifiedUrl.Length/sizeof(WCHAR)] != UNICODE_NULL) { Status = STATUS_INVALID_PARAMETER; __leave; } // CODEWORK: validate the incoming url. // // Call the internal worker func // Status = UlRemoveUrlFromConfigGroup(pInfo->ConfigGroupId, &pInfo->FullyQualifiedUrl); if (NT_SUCCESS(Status) == FALSE) __leave; } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } if (NT_SUCCESS(Status) == FALSE) goto end; end: // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlRemoveUrlFromConfigGroupIoctl /***************************************************************************++ Routine Description: This routine removes all URLs from a configuration group. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlRemoveAllUrlsFromConfigGroupIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS status; PHTTP_REMOVE_ALL_URLS_INFO pInfo = NULL; // // Sanity check. // PAGED_CODE(); // // Ensure it's a control channel. // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*pInfo)) { status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Fetch out the input buffer. // pInfo = (PHTTP_REMOVE_ALL_URLS_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); // // Call the internal worker function. // status = UlRemoveAllUrlsFromConfigGroup( pInfo->ConfigGroupId ); goto end; end: // // Complete the request. // if (status != STATUS_PENDING) { pIrp->IoStatus.Status = status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( status ); } // UlRemoveAllUrlsFromConfigGroupIoctl /***************************************************************************++ Routine Description: This routine queries information associated with an application pool. Note: This is a METHOD_OUT_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlQueryAppPoolInformationIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_APP_POOL_INFO pInfo = NULL; PVOID pMdlBuffer; ULONG length; PVOID pMdlVa; // // sanity check. // PAGED_CODE(); // // better be an application pool // if (!IS_APP_POOL(pIrpSp->FileObject)) { // // Not an application pool. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer looks good // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_APP_POOL_INFO)) { // // input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } pInfo = (PHTTP_APP_POOL_INFO) pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); __try { switch (pInfo->InformationClass) { case HttpAppPoolDemandStartInformation: case HttpAppPoolDemandStartFlagInformation: case HttpAppPoolQueueLengthInformation: case HttpAppPoolStateInformation: // if no outbut buffer passed down in the Irp // that means app is asking for the required // field length if (!pIrp->MdlAddress) { pMdlBuffer = NULL; } else { pMdlBuffer = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, LowPagePriority ); if (pMdlBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } // Probe the user memory to make sure that it's good. pMdlVa = MmGetMdlVirtualAddress(pIrp->MdlAddress); ProbeForWrite( pMdlVa, pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof(UCHAR) ); } Status = UlQueryAppPoolInformation( GET_APP_POOL_PROCESS(pIrpSp->FileObject), pInfo->InformationClass, pMdlBuffer, pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, &length ); if (!NT_SUCCESS(Status)) { __leave; } pIrp->IoStatus.Information = (ULONG_PTR)length; break; default: Status = STATUS_INVALID_PARAMETER; __leave; break; } } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } end: // // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlQueryAppPoolInformationIoctl /***************************************************************************++ Routine Description: This routine sets information associated with an application pool. Note: This is a METHOD_IN_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlSetAppPoolInformationIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_APP_POOL_INFO pInfo; PVOID pMdlBuffer; // // Sanity check // PAGED_CODE(); // // better be an application pool // if (!IS_APP_POOL(pIrpSp->FileObject)) { // // Not an application pool. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer looks good // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_APP_POOL_INFO)) { // // input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Check that the input buffer is valid // if (NULL == pIrp->MdlAddress) { Status = STATUS_INVALID_PARAMETER; goto end; } __try { pInfo = (PHTTP_APP_POOL_INFO) pIrp->AssociatedIrp.SystemBuffer; switch (pInfo->InformationClass) { case HttpAppPoolDemandStartInformation: case HttpAppPoolDemandStartFlagInformation: case HttpAppPoolQueueLengthInformation: case HttpAppPoolStateInformation: // // call the function // pMdlBuffer = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, LowPagePriority ); if (pMdlBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { Status = UlSetAppPoolInformation( GET_APP_POOL_PROCESS(pIrpSp->FileObject), pInfo->InformationClass, pMdlBuffer, pIrpSp->Parameters.DeviceIoControl.OutputBufferLength ); } break; default: Status = STATUS_INVALID_PARAMETER; break; } } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); goto end; } end: // // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlSetAppPoolInformationIoctl /***************************************************************************++ Routine Description: This routine receives an HTTP request. Note: This is a METHOD_OUT_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlReceiveHttpRequestIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_RECEIVE_REQUEST_INFO pInfo = NULL; // // Sanity check. // PAGED_CODE(); // // Ensure this is really an app pool, not a control channel. // if (IS_APP_POOL(pIrpSp->FileObject)) { // // Grab the input buffer // pInfo = (PHTTP_RECEIVE_REQUEST_INFO) pIrp->AssociatedIrp.SystemBuffer; if (NULL == pInfo) { Status = STATUS_INVALID_PARAMETER; goto end; } // // first make sure the output buffer is at least // minimum size. this is important as we require // at least this much space later // UlTrace(ROUTING, ( "UlReceiveHttpRequestIoctl(outbuf=%d, inbuf=%d)\n", pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, pIrpSp->Parameters.DeviceIoControl.InputBufferLength )); if ((pIrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(HTTP_REQUEST)) && (pIrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(HTTP_RECEIVE_REQUEST_INFO))) { Status = UlReceiveHttpRequest( pInfo->RequestId, pInfo->Flags, GET_APP_POOL_PROCESS(pIrpSp->FileObject), pIrp ); } else { Status = STATUS_BUFFER_TOO_SMALL; // Add some padding pIrp->IoStatus.Information = 3 * sizeof(HTTP_REQUEST) / 2; } UlTrace(ROUTING, ( "UlReceiveHttpRequestIoctl: BytesNeeded=%d, status=0x%x\n", pIrp->IoStatus.Information, Status )); } else { Status = STATUS_INVALID_DEVICE_REQUEST; } end: // // Complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlReceiveHttpRequestIoctl /***************************************************************************++ Routine Description: This routine receives entity body data from an HTTP request. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlReceiveEntityBodyIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_RECEIVE_REQUEST_INFO pInfo; PUL_INTERNAL_REQUEST pRequest = NULL; // // Sanity check. // PAGED_CODE(); // // Ensure this is really an app pool, not a control channel. // if (IS_APP_POOL(pIrpSp->FileObject) == FALSE) { Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_RECEIVE_REQUEST_INFO)) { Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Map the incoming connection ID to the corresponding // PUL_HTTP_CONNECTION object. // pInfo = (PHTTP_RECEIVE_REQUEST_INFO)(pIrp->AssociatedIrp.SystemBuffer); // // Now get the request from the request id. // This gets us a reference to the request. // pRequest = UlGetRequestFromId(pInfo->RequestId); if (UL_IS_VALID_INTERNAL_REQUEST(pRequest) == FALSE) { Status = STATUS_INVALID_PARAMETER; goto end; } // // OK, now call the function // Status = UlReceiveEntityBody( GET_APP_POOL_PROCESS(pIrpSp->FileObject), pRequest, pIrp ); if (NT_SUCCESS(Status) == FALSE) goto end; end: if (pRequest != NULL) { UL_DEREFERENCE_INTERNAL_REQUEST(pRequest); pRequest = NULL; } // // Complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlReceiveEntityBodyIoctl /***************************************************************************++ Routine Description: This routine sends an HTTP response. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlSendHttpResponseIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status = STATUS_SUCCESS; PHTTP_SEND_HTTP_RESPONSE_INFO pSendInfo = NULL; PUL_INTERNAL_RESPONSE pResponse = NULL; PHTTP_RESPONSE pHttpResponse = NULL; ULONG Flags; PUL_INTERNAL_REQUEST pRequest = NULL; BOOLEAN ServedFromCache = FALSE; BOOLEAN CaptureCache; BOOLEAN ConnectionClosed = FALSE; // // Sanity check. // PAGED_CODE(); // // Ensure this is really an app pool, not a control channel. // if (IS_APP_POOL(pIrpSp->FileObject) == FALSE) { // // Not an app pool. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*pSendInfo)) { // // Input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } pSendInfo = (PHTTP_SEND_HTTP_RESPONSE_INFO)pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer; // // Probe pSendInfo since we use NEITHER_IO. // __try { ProbeTestForRead( pSendInfo, sizeof(*pSendInfo), sizeof(PVOID) ); ProbeTestForRead( pSendInfo->pEntityChunks, sizeof(HTTP_DATA_CHUNK) * pSendInfo->EntityChunkCount, sizeof(PVOID) ); UlTrace(SEND_RESPONSE, ( "UL!UlSendHttpResponseIoctl - Flags = %X\n", pSendInfo->Flags )); // // UlSendHttpResponse() *must* take a PHTTP_RESPONSE. This will // protect us from those whackos that attempt to build their own // raw response headers. // pHttpResponse = pSendInfo->pHttpResponse; if (pHttpResponse == NULL) { Status = STATUS_INVALID_PARAMETER; goto end; } // // Now get the request from the request id. // This gives us a reference to the request. // pRequest = UlGetRequestFromId(pSendInfo->RequestId); if (pRequest == NULL) { // // Couldn't map the HTTP_REQUEST_ID. // Status = STATUS_INVALID_PARAMETER; goto end; } ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest)); ASSERT(UL_IS_VALID_HTTP_CONNECTION(pRequest->pHttpConn)); // // Make sure only one response header goes back. We can test this // without acquiring the request resource, since the flag is only set // (never reset). // if (1 == InterlockedCompareExchange( (PLONG)&pRequest->SentResponse, 1, 0 )) { // // already sent a response. bad. // Status = STATUS_INVALID_DEVICE_STATE; UlTrace(SEND_RESPONSE, ( "ul!UlSendHttpResponseIoctl(pRequest = %p (%I64x)) %x\n" " Tried to send a second response!\n", pRequest, pRequest->RequestId, Status )); goto end; } // // Also ensure that all previous calls to SendHttpResponse // and SendEntityBody had the MORE_DATA flag set. // if ((pSendInfo->Flags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) { // // Remember if the more data flag is not set. // if (1 == InterlockedCompareExchange( (PLONG)&pRequest->SentLast, 1, 0 )) { Status = STATUS_INVALID_DEVICE_STATE; goto end; } } else if (pRequest->SentLast == 1) { Status = STATUS_INVALID_DEVICE_STATE; UlTrace(SEND_RESPONSE, ( "ul!UlSendHttpResponseIoctl(pRequest = %p (%I64x)) %x\n" " Tried to send again after last send!\n", pRequest, pRequest->RequestId, Status )); goto end; } // // OK, we have the connection. Now capture the incoming // HTTP_RESPONSE structure and map it to our internal // format. // if (pSendInfo->CachePolicy.Policy != HttpCachePolicyNocache) { CaptureCache = pRequest->CachePreconditions; } else { CaptureCache = FALSE; } // // Take the fast path if this is a single memory chunk that needs no // retransmission (<= 64k). // if (CaptureCache == FALSE && pSendInfo->EntityChunkCount == 1 && pSendInfo->pEntityChunks->DataChunkType == HttpDataChunkFromMemory && pSendInfo->pEntityChunks->FromMemory.BufferLength <= MAX_BYTES_BUFFERED ) { Status = UlpFastSendHttpResponse( pSendInfo->pHttpResponse, pSendInfo->pLogData, pSendInfo->pEntityChunks, 1, pSendInfo->Flags, pRequest, pIrp, NULL ); goto end; } Status = UlCaptureHttpResponse( pSendInfo->pHttpResponse, pRequest, pRequest->Version, pRequest->Verb, pSendInfo->EntityChunkCount, pSendInfo->pEntityChunks, UlCaptureNothing, CaptureCache, pSendInfo->pLogData, &pResponse ); } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } if (NT_SUCCESS(Status) == FALSE) goto end; // // Save the captured response in the IRP so we can // dereference it after the IRP completes. // pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pResponse; // // Prepare the response (open files, etc). // Status = UlPrepareHttpResponse( pRequest->Version, pHttpResponse, pResponse ); if (NT_SUCCESS(Status)) { // // At this point, we'll definitely be initiating the // send. Go ahead and mark the IRP as pending, then // guarantee that we'll only return pending from // this point on. // IoMarkIrpPending( pIrp ); pIrp->IoStatus.Status = STATUS_PENDING; // // Try capture to cache and send // if (CaptureCache) { Status = UlCacheAndSendResponse( pRequest, pResponse, GET_APP_POOL_PROCESS( pIrpSp->FileObject ), pSendInfo->Flags, pSendInfo->CachePolicy, &UlpRestartSendHttpResponse, pIrp, &ServedFromCache ); if (NT_SUCCESS(Status) && !ServedFromCache) { // // Send the non-cached response // Status = UlSendHttpResponse( pRequest, pResponse, pSendInfo->Flags, &UlpRestartSendHttpResponse, pIrp ); } } else { // // Non-cacheable request/response, send response directly. // Status = UlSendHttpResponse( pRequest, pResponse, pSendInfo->Flags, &UlpRestartSendHttpResponse, pIrp ); } } else { // // BUGBUG: Do custom error thang here. // NTSTATUS CloseStatus; pIrp->IoStatus.Status = Status; CloseStatus = UlCloseConnection( pRequest->pHttpConn->pConnection, TRUE, &UlpRestartSendHttpResponse, pIrp ); ASSERT( CloseStatus == STATUS_PENDING ); ConnectionClosed = TRUE; // UlCloseConnection always returns STATUS_PENDING // but we want to return the a proper error code here. // E.G. If the supplied file - as filename data chunk - // not found we will return STATUS_OBJECT_NAME_INVALID // as its returned by UlPrepareHttpResponse. } // paulmcd: is this the right time to deref? // // DEREFERENCE_HTTP_CONNECTION( pHttpConnection ); if (Status != STATUS_PENDING && !ConnectionClosed) { // // UlSendHttpResponse either completed in-line // (extremely unlikely) or failed (much more // likely). Fake a completion to the completion // routine so that the IRP will get completed // properly, then map the return code to // STATUS_PENDING, since we've already marked // the IRP as such. // UlpRestartSendHttpResponse( pIrp, Status, 0 ); Status = STATUS_PENDING; } end: if (pRequest != NULL) { UL_DEREFERENCE_INTERNAL_REQUEST(pRequest); pRequest = NULL; } // // Complete the request. // if (Status != STATUS_PENDING && !ConnectionClosed) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlSendHttpResponseIoctl /***************************************************************************++ Routine Description: This routine sends an HTTP entity body. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlSendEntityBodyIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_SEND_HTTP_RESPONSE_INFO pSendInfo; PUL_INTERNAL_RESPONSE pResponse; ULONG Flags; PUL_INTERNAL_REQUEST pRequest = NULL; BOOLEAN ConnectionClosed = FALSE; // // Sanity check. // PAGED_CODE(); // // Ensure this is really an app pool, not a control channel. // if (IS_APP_POOL(pIrpSp->FileObject) == FALSE) { // // Not an app pool. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*pSendInfo)) { // // Input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } pSendInfo = (PHTTP_SEND_HTTP_RESPONSE_INFO)pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer; // // Probe pSendInfo since we use NEITHER_IO. // __try { ProbeTestForRead( pSendInfo, sizeof(*pSendInfo), sizeof(PVOID) ); } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); goto end; } UlTrace(SEND_RESPONSE, ( "UL!UlSendEntityBodyIoctl - Flags = %X\n", pSendInfo->Flags )); // // Now get the request from the request id. // This gives us a reference to the request. // pRequest = UlGetRequestFromId(pSendInfo->RequestId); if (pRequest == NULL) { // // Couldn't map the HTTP_REQUEST_ID. // Status = STATUS_INVALID_PARAMETER; goto end; } ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest)); ASSERT(UL_IS_VALID_HTTP_CONNECTION(pRequest->pHttpConn)); // // Ensure a response has already been sent. We can test this without // acquiring the request resource, since the flag is only set (never // reset). // if (pRequest->SentResponse == 0) { // // The application is sending entity without first having // send a response header. This is generally an error, however // we allow the application to override this by passing // the HTTP_SEND_RESPONSE_FLAG_RAW_HEADER flag. // if (pSendInfo->Flags & HTTP_SEND_RESPONSE_FLAG_RAW_HEADER) { UlTrace(SEND_RESPONSE, ( "ul!UlSendEntityBodyIoctl(pRequest = %p (%I64x))\n" " Intentionally sending raw header!\n", pRequest, pRequest->RequestId )); if (1 == InterlockedCompareExchange( (PLONG)&pRequest->SentResponse, 1, 0 )) { Status = STATUS_INVALID_DEVICE_STATE; goto end; } } else { Status = STATUS_INVALID_DEVICE_STATE; UlTrace(SEND_RESPONSE, ( "ul!UlSendEntityBodyIoctl(pRequest = %p (%I64x)) %x\n" " No response yet!\n", pRequest, pRequest->RequestId, Status )); goto end; } } // // Also ensure that all previous calls to SendHttpResponse // and SendEntityBody had the MORE_DATA flag set. // if ((pSendInfo->Flags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) { // // Remember that this was the last send. We shouldn't // get any more data after this. // if (1 == InterlockedCompareExchange( (PLONG)&pRequest->SentLast, 1, 0 )) { Status = STATUS_INVALID_DEVICE_STATE; goto end; } } else if (pRequest->SentLast == 1) { Status = STATUS_INVALID_DEVICE_STATE; UlTrace(SEND_RESPONSE, ( "ul!UlSendEntityBodyIoctl(pRequest = %p (%I64x)) %x\n" " Tried to send again after last send!\n", pRequest, pRequest->RequestId, Status )); goto end; } ASSERT(pSendInfo->pHttpResponse == NULL); __try { // // Take the fast path if this is a single memory chunk that needs no // retransmission (<= 64k). // if (pSendInfo->EntityChunkCount == 1 && pSendInfo->pEntityChunks->DataChunkType == HttpDataChunkFromMemory && pSendInfo->pEntityChunks->FromMemory.BufferLength <= MAX_BYTES_BUFFERED ) { Status = UlpFastSendHttpResponse( NULL, pSendInfo->pLogData, pSendInfo->pEntityChunks, 1, pSendInfo->Flags, pRequest, pIrp, NULL ); goto end; } // // OK, we have the connection. Now capture the incoming // HTTP_RESPONSE structure and map it to our internal // format. // Status = UlCaptureHttpResponse( NULL, pRequest, pRequest->Version, pRequest->Verb, pSendInfo->EntityChunkCount, pSendInfo->pEntityChunks, UlCaptureNothing, FALSE, pSendInfo->pLogData, &pResponse ); } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } if (NT_SUCCESS(Status) == FALSE) goto end; // // Save the captured response in the IRP so we can // dereference it after the IRP completes. // pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pResponse; // // Prepare the response (open files, etc). // Status = UlPrepareHttpResponse( pRequest->Version, NULL, pResponse ); if (NT_SUCCESS(Status)) { // // At this point, we'll definitely be initiating the // send. Go ahead and mark the IRP as pending, then // guarantee that we'll only return pending from // this point on. // IoMarkIrpPending( pIrp ); pIrp->IoStatus.Status = STATUS_PENDING; // // Send the response // Status = UlSendHttpResponse( pRequest, pResponse, pSendInfo->Flags, &UlpRestartSendHttpResponse, pIrp ); } else { // // BUGBUG: Do custom error thang here. // NTSTATUS CloseStatus; pIrp->IoStatus.Status = Status; CloseStatus = UlCloseConnection( pRequest->pHttpConn->pConnection, TRUE, &UlpRestartSendHttpResponse, pIrp ); ASSERT( CloseStatus == STATUS_PENDING ); ConnectionClosed = TRUE; } // paulmcd: is this the right time to deref? // // DEREFERENCE_HTTP_CONNECTION( pHttpConnection ); if (Status != STATUS_PENDING && !ConnectionClosed) { // // UlSendHttpResponse either completed in-line // (extremely unlikely) or failed (much more // likely). Fake a completion to the completion // routine so that the IRP will get completed // properly, then map the return code to // STATUS_PENDING, since we've already marked // the IRP as such. // UlpRestartSendHttpResponse( pIrp, Status, 0 ); Status = STATUS_PENDING; } end: if (pRequest != NULL) { UL_DEREFERENCE_INTERNAL_REQUEST(pRequest); pRequest = NULL; } // // Complete the request. // if (Status != STATUS_PENDING && !ConnectionClosed) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlSendEntityBodyIoctl /***************************************************************************++ Routine Description: This routine flushes a URL or URL tree from the response cache. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlFlushResponseCacheIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_FLUSH_RESPONSE_CACHE_INFO pInfo = NULL; // // sanity check. // PAGED_CODE(); // better be an app pool // if (IS_APP_POOL(pIrpSp->FileObject) == FALSE) { // // Not an app pool. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_FLUSH_RESPONSE_CACHE_INFO)) { // bad buffer // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // Fetch out the input buffer // pInfo = (PHTTP_FLUSH_RESPONSE_CACHE_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); // does it look appropriate? // if (pInfo->FullyQualifiedUrl.MaximumLength < pInfo->FullyQualifiedUrl.Length || pInfo->FullyQualifiedUrl.Length == 0 || (pInfo->FullyQualifiedUrl.Length % sizeof(WCHAR)) != 0 || pInfo->FullyQualifiedUrl.Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto end; } // Going to access the url string from user mode memory // __try { // good memory? // ProbeTestForRead(pInfo->FullyQualifiedUrl.Buffer, pInfo->FullyQualifiedUrl.Length + sizeof(WCHAR), sizeof(WCHAR)); // must be null terminated // if (pInfo->FullyQualifiedUrl.Buffer[pInfo->FullyQualifiedUrl.Length/sizeof(WCHAR)] != UNICODE_NULL) { Status = STATUS_INVALID_PARAMETER; __leave; } // check the flags // if (pInfo->Flags != (pInfo->Flags & HTTP_FLUSH_RESPONSE_FLAG_VALID)) { Status = STATUS_INVALID_PARAMETER; __leave; } // Call the internal worker func // UlFlushCacheByUri( pInfo->FullyQualifiedUrl.Buffer, pInfo->FullyQualifiedUrl.Length, pInfo->Flags, GET_APP_POOL_PROCESS( pIrpSp->FileObject ) ); Status = STATUS_SUCCESS; if (NT_SUCCESS(Status) == FALSE) __leave; } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } if (NT_SUCCESS(Status) == FALSE) goto end; end: // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlFlushResponseCacheIoctl /***************************************************************************++ Routine Description: This routine waits for demand start notifications. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlWaitForDemandStartIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; // // sanity check. // PAGED_CODE(); // // This had better be an app pool. // if (IS_APP_POOL(pIrpSp->FileObject) == FALSE) { // // Not an app pool. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // make the call // UlTrace(IOCTL, ("UlWaitForDemandStartIoctl: pAppPoolProcess=%p, pIrp=%p\n", GET_APP_POOL_PROCESS(pIrpSp->FileObject), pIrp )); Status = UlWaitForDemandStart( GET_APP_POOL_PROCESS(pIrpSp->FileObject), pIrp ); end: // // complete the request? // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlWaitForDemandStartIoctl /***************************************************************************++ Routine Description: This routine waits for the client to initiate a disconnect. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlWaitForDisconnectIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS status; PHTTP_WAIT_FOR_DISCONNECT_INFO pInfo; PUL_HTTP_CONNECTION pHttpConn; // // Sanity check. // PAGED_CODE(); // // This had better be an app pool. // if (IS_APP_POOL(pIrpSp->FileObject) == FALSE) { // // Not an app pool. // status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Validate the input buffer. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*pInfo)) { status = STATUS_BUFFER_TOO_SMALL; goto end; } pInfo = (PHTTP_WAIT_FOR_DISCONNECT_INFO)pIrp->AssociatedIrp.SystemBuffer; // // Chase down the connection. // pHttpConn = UlGetConnectionFromId( pInfo->ConnectionId ); if (!UL_IS_VALID_HTTP_CONNECTION(pHttpConn)) { status = STATUS_INVALID_PARAMETER; goto end; } // // Do it. // status = UlWaitForDisconnect( GET_APP_POOL_PROCESS(pIrpSp->FileObject), pHttpConn, pIrp ); end: // // Complete the request? // if (status != STATUS_PENDING) { pIrp->IoStatus.Status = status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( status ); } // UlWaitForDisconnectIoctl // // Private functions. // /***************************************************************************++ Routine Description: Completion routine for UlSendHttpResponse(). Arguments: pCompletionContext - Supplies an uninterpreted context value as passed to the asynchronous API. In this case, it's actually a pointer to the user's IRP. Status - Supplies the final completion status of the asynchronous API. Information - Optionally supplies additional information about the completed operation, such as the number of bytes transferred. --***************************************************************************/ VOID UlpRestartSendHttpResponse( IN PVOID pCompletionContext, IN NTSTATUS Status, IN ULONG_PTR Information ) { PIRP pIrp; PIO_STACK_LOCATION pIrpSp; PUL_INTERNAL_RESPONSE pResponse; // // Snag the IRP from the completion context, fill in the completion // status, then complete the IRP. // pIrp = (PIRP)pCompletionContext; pIrpSp = IoGetCurrentIrpStackLocation( pIrp ); pResponse = (PUL_INTERNAL_RESPONSE)( pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer ); ASSERT( UL_IS_VALID_INTERNAL_RESPONSE( pResponse ) ); UL_DEREFERENCE_INTERNAL_RESPONSE( pResponse ); // // Only overwrite the status field if it hasn't already been set // to an error // if (NT_SUCCESS(pIrp->IoStatus.Status)) pIrp->IoStatus.Status = Status; pIrp->IoStatus.Information = Information; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } // UlpRestartSendHttpResponse /***************************************************************************++ Routine Description: This routine adds a new transient URL prefix. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlAddTransientUrlIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_TRANSIENT_URL_INFO pInfo = NULL; // // sanity check. // PAGED_CODE(); // better be an application pool // if (IS_APP_POOL(pIrpSp->FileObject) == FALSE) { // // Not an app pool. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_TRANSIENT_URL_INFO)) { // bad buffer // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // Fetch out the input buffer // pInfo = (PHTTP_TRANSIENT_URL_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); // does it look appropriate? // if (pInfo->FullyQualifiedUrl.MaximumLength < pInfo->FullyQualifiedUrl.Length || pInfo->FullyQualifiedUrl.Length == 0 || (pInfo->FullyQualifiedUrl.Length % sizeof(WCHAR)) != 0 || pInfo->FullyQualifiedUrl.Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto end; } // Going to access the url string from user mode memory // __try { // good memory? // ProbeTestForRead(pInfo->FullyQualifiedUrl.Buffer, pInfo->FullyQualifiedUrl.Length + sizeof(WCHAR), sizeof(WCHAR)); // must be null terminated // if (pInfo->FullyQualifiedUrl.Buffer[pInfo->FullyQualifiedUrl.Length/sizeof(WCHAR)] != UNICODE_NULL) { Status = STATUS_INVALID_PARAMETER; __leave; } // CODEWORK: validate the incoming url. // // Call the internal worker func // Status = UlAddTransientUrl( UlAppPoolObjectFromProcess( GET_APP_POOL_PROCESS(pIrpSp->FileObject) ), &pInfo->FullyQualifiedUrl ); if (!NT_SUCCESS(Status)) __leave; } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } end: // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlAddTransientUrlIoctl /***************************************************************************++ Routine Description: This routine removes a transient URL prefix. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlRemoveTransientUrlIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_TRANSIENT_URL_INFO pInfo = NULL; // // sanity check. // PAGED_CODE(); // better be an application pool // if (IS_APP_POOL(pIrpSp->FileObject) == FALSE) { // // Not an app pool. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_TRANSIENT_URL_INFO)) { // bad buffer // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // Fetch out the input buffer // pInfo = (PHTTP_TRANSIENT_URL_INFO)pIrp->AssociatedIrp.SystemBuffer; ASSERT(pInfo != NULL); // does it look appropriate? // if (pInfo->FullyQualifiedUrl.MaximumLength < pInfo->FullyQualifiedUrl.Length || pInfo->FullyQualifiedUrl.Length == 0 || (pInfo->FullyQualifiedUrl.Length % sizeof(WCHAR)) != 0 || pInfo->FullyQualifiedUrl.Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto end; } // Going to access the url string from user mode memory // __try { // good memory? // ProbeTestForRead(pInfo->FullyQualifiedUrl.Buffer, pInfo->FullyQualifiedUrl.Length + sizeof(WCHAR), sizeof(WCHAR)); // must be null terminated // if (pInfo->FullyQualifiedUrl.Buffer[pInfo->FullyQualifiedUrl.Length/sizeof(WCHAR)] != UNICODE_NULL) { Status = STATUS_INVALID_PARAMETER; __leave; } // CODEWORK: validate the incoming url. // // Call the internal worker func // Status = UlRemoveTransientUrl( UlAppPoolObjectFromProcess( GET_APP_POOL_PROCESS(pIrpSp->FileObject) ), &pInfo->FullyQualifiedUrl ); if (!NT_SUCCESS(Status)) __leave; } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); } end: // complete the request. // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlRemoveTransientUrlIoctl /***************************************************************************++ Routine Description: This routine accepts a raw connection. Note: This is a METHOD_OUT_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlFilterAcceptIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; // // Sanity check. // PAGED_CODE(); // // This had better be a filter channel. // if (!IS_FILTER_PROCESS(pIrpSp->FileObject)) { // // Not a filter channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // make the call // Status = UlFilterAccept( GET_FILTER_PROCESS(pIrpSp->FileObject), pIrp ); end: // // complete the request? // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlFilterAcceptIoctl /***************************************************************************++ Routine Description: This routine closes a raw connection. Note: This is a METHOD_BUFFERED IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlFilterCloseIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; HTTP_RAW_CONNECTION_ID ConnectionId; PUX_FILTER_CONNECTION pConnection; // // Sanity check. // PAGED_CODE(); // // Set up locals so we know how to clean up on exit. // pConnection = NULL; // // This had better be a filter channel. // if (!IS_FILTER_PROCESS(pIrpSp->FileObject)) { // // Not a filter channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ConnectionId)) { // // Input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Map the incoming connection ID to the corresponding // UX_FILTER_CONNECTION object. // ConnectionId = *((PHTTP_RAW_CONNECTION_ID)pIrp->AssociatedIrp.SystemBuffer); pConnection = UlGetRawConnectionFromId(ConnectionId); if (!pConnection) { Status = STATUS_INVALID_PARAMETER; goto end; } ASSERT(IS_VALID_FILTER_CONNECTION(pConnection)); // // make the call // Status = UlFilterClose( GET_FILTER_PROCESS(pIrpSp->FileObject), pConnection, pIrp ); end: if (pConnection) { DEREFERENCE_FILTER_CONNECTION(pConnection); } // // complete the request? // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlFilterCloseIoctl /***************************************************************************++ Routine Description: This routine reads data from a raw connection. Note: This is a METHOD_OUT_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlFilterRawReadIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; HTTP_RAW_CONNECTION_ID ConnectionId; PUX_FILTER_CONNECTION pConnection; // // Sanity check. // PAGED_CODE(); // // Set up locals so we know how to clean up on exit. // pConnection = NULL; // // This had better be a filter channel. // if (!IS_FILTER_PROCESS(pIrpSp->FileObject)) { // // Not a filter channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ConnectionId)) { // // Input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Map the incoming connection ID to the corresponding // UX_FILTER_CONNECTION object. // ConnectionId = *((PHTTP_RAW_CONNECTION_ID)pIrp->AssociatedIrp.SystemBuffer); pConnection = UlGetRawConnectionFromId(ConnectionId); if (!pConnection) { Status = STATUS_INVALID_PARAMETER; goto end; } ASSERT(IS_VALID_FILTER_CONNECTION(pConnection)); // // make the call // Status = UlFilterRawRead( GET_FILTER_PROCESS(pIrpSp->FileObject), pConnection, pIrp ); end: if (pConnection) { DEREFERENCE_FILTER_CONNECTION(pConnection); } // // complete the request? // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlFilterRawReadIoctl /***************************************************************************++ Routine Description: This routine writes data to a raw connection. Note: This is a METHOD_IN_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlFilterRawWriteIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; HTTP_RAW_CONNECTION_ID ConnectionId; PUX_FILTER_CONNECTION pConnection; BOOLEAN MarkedPending; // // Sanity check. // PAGED_CODE(); // // Set up locals so we know how to clean up on exit. // pConnection = NULL; MarkedPending = FALSE; // // This had better be a filter channel. // if (!IS_FILTER_PROCESS(pIrpSp->FileObject)) { // // Not a filter channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ConnectionId)) { // // Input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Ensure that there's an output buffer. // if (!pIrp->MdlAddress) { Status = STATUS_INVALID_PARAMETER; goto end; } // // Map the incoming connection ID to the corresponding // UX_FILTER_CONNECTION object. // ConnectionId = *((PHTTP_RAW_CONNECTION_ID)pIrp->AssociatedIrp.SystemBuffer); pConnection = UlGetRawConnectionFromId(ConnectionId); if (!pConnection) { Status = STATUS_INVALID_PARAMETER; goto end; } ASSERT(IS_VALID_FILTER_CONNECTION(pConnection)); // // make the call // IoMarkIrpPending(pIrp); MarkedPending = TRUE; Status = UlFilterRawWrite( GET_FILTER_PROCESS(pIrpSp->FileObject), pConnection, pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, pIrp ); end: if (pConnection) { DEREFERENCE_FILTER_CONNECTION(pConnection); } // // complete the request? // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); if (MarkedPending) { // // Since we marked the IRP pending, we should return pending. // Status = STATUS_PENDING; } } else { // // If we're returning pending, the IRP better be marked pending. // ASSERT(MarkedPending); } RETURN( Status ); } // UlFilterRawWriteIoctl /***************************************************************************++ Routine Description: This routine reads data from an http application. Note: This is a METHOD_OUT_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlFilterAppReadIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; HTTP_RAW_CONNECTION_ID ConnectionId; PUX_FILTER_CONNECTION pConnection; PHTTP_FILTER_BUFFER pFiltBuffer; // // Sanity check. // PAGED_CODE(); // // Set up locals so we know how to clean up on exit. // pConnection = NULL; // // This had better be a filter channel. // if (!IS_FILTER_PROCESS(pIrpSp->FileObject)) { // // Not a filter channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_FILTER_BUFFER)) { // // Input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Ensure the output buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HTTP_FILTER_BUFFER)) { // // Output buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Grab the filter buffer object. // pFiltBuffer = (PHTTP_FILTER_BUFFER) pIrp->AssociatedIrp.SystemBuffer; // // Map the incoming connection ID to the corresponding // UX_FILTER_CONNECTION object. // ConnectionId = pFiltBuffer->Reserved; pConnection = UlGetRawConnectionFromId(ConnectionId); if (!pConnection) { Status = STATUS_INVALID_PARAMETER; goto end; } ASSERT(IS_VALID_FILTER_CONNECTION(pConnection)); // // make the call // Status = UlFilterAppRead( GET_FILTER_PROCESS(pIrpSp->FileObject), pConnection, pIrp ); end: if (pConnection) { DEREFERENCE_FILTER_CONNECTION(pConnection); } // // complete the request? // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlFilterAppReadIoctl /***************************************************************************++ Routine Description: This routine writes data to an http application. Note: This is a METHOD_IN_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlFilterAppWriteIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; HTTP_RAW_CONNECTION_ID ConnectionId; PUX_FILTER_CONNECTION pConnection; BOOLEAN MarkedPending; PHTTP_FILTER_BUFFER pFiltBuffer; // // Sanity check. // PAGED_CODE(); // // Set up locals so we know how to clean up on exit. // pConnection = NULL; MarkedPending = FALSE; // // This had better be a filter channel. // if (!IS_FILTER_PROCESS(pIrpSp->FileObject)) { // // Not a filter channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_FILTER_BUFFER)) { // // Input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Grab the filter buffer object. // pFiltBuffer = (PHTTP_FILTER_BUFFER) pIrp->AssociatedIrp.SystemBuffer; // // Map the incoming connection ID to the corresponding // UX_FILTER_CONNECTION object. // ConnectionId = pFiltBuffer->Reserved; pConnection = UlGetRawConnectionFromId(ConnectionId); if (!pConnection) { Status = STATUS_INVALID_PARAMETER; goto end; } ASSERT(IS_VALID_FILTER_CONNECTION(pConnection)); // // make the call // IoMarkIrpPending(pIrp); MarkedPending = TRUE; Status = UlFilterAppWrite( GET_FILTER_PROCESS(pIrpSp->FileObject), pConnection, pIrp ); end: if (pConnection) { DEREFERENCE_FILTER_CONNECTION(pConnection); } // // complete the request? // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); if (MarkedPending) { // // Since we marked the IRP pending, we should return pending. // Status = STATUS_PENDING; } } else { // // If we're returning pending, the IRP better be marked pending. // ASSERT(MarkedPending); } RETURN( Status ); } // UlFilterAppWriteIoctl /***************************************************************************++ Routine Description: This routine asks the SSL helper for a client certificate. Note: This is a METHOD_OUT_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlReceiveClientCertIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PHTTP_FILTER_RECEIVE_CLIENT_CERT_INFO pReceiveCertInfo; HTTP_RAW_CONNECTION_ID ConnectionId; PUL_HTTP_CONNECTION pHttpConn; // // Sanity check. // PAGED_CODE(); // // Set up locals so we know how to clean up on exit. // pHttpConn = NULL; // // This had better be an app pool. // if (IS_APP_POOL(pIrpSp->FileObject) == FALSE) { // // Not an app pool. // Status = STATUS_INVALID_DEVICE_REQUEST; goto end; } // // Ensure the input buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_FILTER_RECEIVE_CLIENT_CERT_INFO)) { // // Input buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Ensure the output buffer is large enough. // if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HTTP_SSL_CLIENT_CERT_INFO)) { // // Output buffer too small. // Status = STATUS_BUFFER_TOO_SMALL; goto end; } // // Grab the cert receive object. // pReceiveCertInfo = (PHTTP_FILTER_RECEIVE_CLIENT_CERT_INFO) pIrp->AssociatedIrp.SystemBuffer; // // Map the incoming connection ID to the corresponding // HTTP_CONNECTION object. // ConnectionId = pReceiveCertInfo->ConnectionId; pHttpConn = UlGetConnectionFromId(ConnectionId); if (!pHttpConn) { Status = STATUS_INVALID_PARAMETER; goto end; } ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConn)); // // make the call // Status = UlReceiveClientCert( GET_APP_POOL_PROCESS(pIrpSp->FileObject), &pHttpConn->pConnection->FilterInfo, pReceiveCertInfo->Flags, pIrp ); end: if (pHttpConn) { UL_DEREFERENCE_HTTP_CONNECTION(pHttpConn); } // // complete the request? // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlFilterReceiveClientCertIoctl /***************************************************************************++ Routine Description: This routine returns the perfmon counter data for this driver Note: This is a METHOD_OUT_DIRECT IOCTL. Arguments: pIrp - Supplies a pointer to the IO request packet. pIrpSp - Supplies a pointer to the IO stack location to use for this request. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlGetCountersIoctl( IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp ) { NTSTATUS Status; PUL_CONTROL_CHANNEL pControlChannel; ULONG Length; PVOID pMdlBuffer; PVOID pMdlVa; HTTP_COUNTER_GROUP CounterGroup; // // Sanity check. // PAGED_CODE(); // // Set up locals so we know how to clean up on exit. // Status = STATUS_SUCCESS; Length = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength; // // better be a control channel // if (IS_CONTROL_CHANNEL(pIrpSp->FileObject) == FALSE) { // // Not a control channel. // Status = STATUS_INVALID_DEVICE_REQUEST; goto End; } pControlChannel = GET_CONTROL_CHANNEL(pIrpSp->FileObject); if (IS_VALID_CONTROL_CHANNEL(pControlChannel) == FALSE) { Status = STATUS_INVALID_PARAMETER; goto End; } // // Find out which type of counters are requested // if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(HTTP_COUNTER_GROUP)) { Status = STATUS_INVALID_PARAMETER; goto End; } CounterGroup = *((HTTP_COUNTER_GROUP *) pIrp->AssociatedIrp.SystemBuffer); // Crack IRP and get MDL contianing user's buffer // Crack MDL to get user's buffer __try { // if no outbut buffer pass down in the Irp // that means app is asking for the required // field length if (!pIrp->MdlAddress) { pMdlVa = NULL; } else { pMdlBuffer = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, LowPagePriority ); if (pMdlBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } // Also make sure that user buffer was good pMdlVa = MmGetMdlVirtualAddress(pIrp->MdlAddress); ProbeForWrite( pMdlVa, Length, sizeof(UCHAR) ); } // // Call support function to gather apropriate counter blocks // and place in user's buffer. // if ( HttpCounterGroupGlobal == CounterGroup ) { Status = UlGetGlobalCounters( pMdlVa, Length, &Length ); } else if ( HttpCounterGroupSite == CounterGroup ) { ULONG Blocks; Status = UlGetSiteCounters( pMdlVa, Length, &Length, &Blocks ); } else { Status = STATUS_NOT_IMPLEMENTED; __leave; } if (!NT_SUCCESS(Status)) { // // If not returning STATUS_SUCCESS, // IoStatus.Information *must* be 0. // pIrp->IoStatus.Information = 0; __leave; } else { pIrp->IoStatus.Information = (ULONG_PTR)Length; } } __except( UL_EXCEPTION_FILTER() ) { Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode()); pIrp->IoStatus.Information = 0; } End: // // complete the request? // if (Status != STATUS_PENDING) { pIrp->IoStatus.Status = Status; UlCompleteRequest( pIrp, g_UlPriorityBoost ); } RETURN( Status ); } // UlGetCountersIoctl