windows-nt/Source/XPSP1/NT/inetsrv/iis/iisrearc/ul/drv/ioctl.cxx
2020-09-26 16:20:57 +08:00

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