4402 lines
101 KiB
C++
4402 lines
101 KiB
C++
/*++
|
|
|
|
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
|