Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

584 lines
17 KiB

/*++
Copyright (c) 1998-2002 Microsoft Corporation
Module Name:
create.c
Abstract:
This module contains code for opening a handle to UL.
Author:
Keith Moore (keithmo) 10-Jun-1998
Revision History:
--*/
#include "precomp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, UlCreate )
#endif // ALLOC_PRAGMA
#define IS_NAMED_FILE_OBJECT(pFileObject) \
((pFileObject)->FileName.Length != 0)
//
// Public functions.
//
/***************************************************************************++
Routine Description:
This is the routine that handles Create IRPs in Http.sys. Create IRPs are
issued when the file object is created.
Control Channel (\Device\Http\Control)
- unnamed only
- open only, create to fail.
- Open will be allowed by any user.
- EA must have proper major/minorversion, everything else must be NULL/0
AppPool (\Device\Http\AppPool)
- can be unnamed or named
- unnamed --> anyone can create, no one can open (server API customers)
- named --> admin only can create, anyone with correct SD can open
(IIS WAS + Worker process)
- EA must have proper major/minorversion, everything else must be NULL/0
Filter (\Device\Http\Filter)
- only named and MUST be either SSLFilterChannel or SSLClientFilterChannel.
- SSLFilterChannel can be created only by admin/local system, opened with
correct SD.
- SSLClientFilterChannel can be created by anyone, opened by anyone
with correct SD, but only if EnableHttpClient is set
- EA must have proper major/minorversion, everything else must be NULL/0
Server (\Device\Http\Server\)
- only unnamed
- Create only, open to fail.
- can be done by anyone.
- Should be allowed only if EnableHttpClient is present.
- EA must have major/minorversion, server & TRANSPORT_ADDRESS structure.
Proxy is optional.
Arguments:
pDeviceObject - Supplies a pointer to the target device object.
pIrp - Supplies a pointer to IO request packet.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlCreate(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS status;
PIO_STACK_LOCATION pIrpSp;
PFILE_OBJECT pFileObject = NULL;
PFILE_FULL_EA_INFORMATION pEaBuffer;
PHTTP_OPEN_PACKET pOpenPacket;
UCHAR createDisposition;
PWSTR pName = NULL;
USHORT nameLength;
PIO_SECURITY_CONTEXT pSecurityContext;
STRING CompareVersionName;
STRING EaName;
PWSTR pSafeName = NULL;
//
// Sanity check.
//
PAGED_CODE();
UL_ENTER_DRIVER( "UlCreate", pIrp );
#if defined(_WIN64)
//
// We do not support 32-bit processes on 64-bit platforms.
//
if (IoIs32bitProcess(pIrp))
{
status = STATUS_NOT_SUPPORTED;
goto complete;
}
#endif
//
// Find and validate the open packet.
//
pEaBuffer = (PFILE_FULL_EA_INFORMATION)(pIrp->AssociatedIrp.SystemBuffer);
if (pEaBuffer == NULL)
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
RtlInitString(&CompareVersionName, HTTP_OPEN_PACKET_NAME);
EaName.MaximumLength = pEaBuffer->EaNameLength + 1;
EaName.Length = pEaBuffer->EaNameLength;
EaName.Buffer = pEaBuffer->EaName;
if ( RtlEqualString(&CompareVersionName, &EaName, FALSE) )
{
//
// Found the version information in the EA
//
if( pEaBuffer->EaValueLength != sizeof(*pOpenPacket) )
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
if(pEaBuffer->NextEntryOffset != 0)
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
pOpenPacket = (PHTTP_OPEN_PACKET)
(pEaBuffer->EaName + pEaBuffer->EaNameLength + 1 );
ASSERT(pOpenPacket == ALIGN_UP_POINTER(pOpenPacket, PVOID));
//
// For now, we'll fail if the incoming version doesn't EXACTLY match
// the expected version. In future, we may need to be a bit more
// flexible to allow down-level clients.
//
if (pOpenPacket->MajorVersion != HTTP_INTERFACE_VERSION_MAJOR ||
pOpenPacket->MinorVersion != HTTP_INTERFACE_VERSION_MINOR)
{
status = STATUS_REVISION_MISMATCH;
goto complete;
}
if(pDeviceObject != g_pUcServerDeviceObject &&
(pOpenPacket->ProxyNameLength != 0 ||
pOpenPacket->ServerNameLength != 0 ||
pOpenPacket->TransportAddressLength != 0 ||
pOpenPacket->pProxyName != NULL ||
pOpenPacket->pServerName != NULL ||
pOpenPacket->pTransportAddress != NULL))
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
}
else
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
//
// Snag the current IRP stack pointer, then extract the creation
// disposition. IO stores this as the high byte of the Options field.
// Also snag the file object; we'll need it often.
//
pIrpSp = IoGetCurrentIrpStackLocation( pIrp );
createDisposition = (UCHAR)( pIrpSp->Parameters.Create.Options >> 24 );
pFileObject = pIrpSp->FileObject;
pSecurityContext = pIrpSp->Parameters.Create.SecurityContext;
ASSERT( pSecurityContext != NULL );
//
// Determine if this is a request to open a control channel or
// open/create an app pool.
//
if (pDeviceObject == g_pUlControlDeviceObject)
{
//
// It's a control channel.
//
// Validate the creation disposition. We allow open only.
//
if (createDisposition != FILE_OPEN)
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
// These things can't be named
if (IS_NAMED_FILE_OBJECT(pFileObject))
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
ASSERT(pFileObject->FileName.Buffer == NULL);
UlTrace(OPEN_CLOSE, (
"UlCreate: opening a control channel: %p\n",
pFileObject
));
//
// Open the control channel.
//
status = UlCreateControlChannel(GET_PP_CONTROL_CHANNEL(pFileObject));
if (NT_SUCCESS(status))
{
ASSERT( GET_CONTROL_CHANNEL(pFileObject) != NULL );
MARK_VALID_CONTROL_CHANNEL( pFileObject );
}
}
else if (pDeviceObject == g_pUlFilterDeviceObject)
{
//
// It's a filter channel - It has to be named and has to be either
// a client or a server filter channel.
//
if (!IS_NAMED_FILE_OBJECT(pFileObject))
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
ASSERT(L'\\' == pFileObject->FileName.Buffer[0]);
pName = pFileObject->FileName.Buffer + 1;
nameLength = pFileObject->FileName.Length - sizeof(WCHAR);
pSafeName = UL_ALLOCATE_POOL(
PagedPool,
nameLength + sizeof(WCHAR),
UL_STRING_LOG_BUFFER_POOL_TAG
);
if(pSafeName == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto complete;
}
RtlCopyMemory(pSafeName, pName, nameLength);
pSafeName[nameLength/sizeof(WCHAR)] = L'\0';
pName = pSafeName;
if(IsServerFilterChannel(pName, nameLength))
{
// Yes - it's a filter channel. We'll allow Create or Open but
// both have to be admin only.
//
// If it's create, we'll do an access check
//
if(createDisposition == FILE_CREATE)
{
status = UlAccessCheck(
g_pAdminAllSystemAll,
pSecurityContext->AccessState,
pSecurityContext->DesiredAccess,
pIrp->RequestorMode,
pName
);
if(!NT_SUCCESS(status))
{
goto complete;
}
}
else if(createDisposition == FILE_OPEN)
{
// We are opening an existing channel - the access check
// will be done inside UlAttachFilterProcess
}
else
{
// Neither FILE_CREATE nor FILE_OPEN. Bail!
status = STATUS_INVALID_PARAMETER;
goto complete;
}
UlTrace(OPEN_CLOSE, (
"UlCreate: opening a server filter channel: %p, %.*ls\n",
pFileObject, nameLength / sizeof(WCHAR), pName
));
}
else if(IsClientFilterChannel(pName, nameLength))
{
// It's a client - Only Create. Also, make sure that the client
// code is really enabled.
if (createDisposition != FILE_CREATE || !g_HttpClientEnabled)
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
UlTrace(OPEN_CLOSE, (
"UlCreate: opening a client filter channel: %p, %.*ls\n",
pFileObject, nameLength / sizeof(WCHAR), pName
));
//
// No access checks for the client!
//
}
else
{
//
// If it is neither server nor client filter channel, fail the
// call.
//
status = STATUS_INVALID_PARAMETER;
goto complete;
}
status = UlAttachFilterProcess(
pName,
nameLength,
(BOOLEAN)(createDisposition == FILE_CREATE),
pSecurityContext->AccessState,
pSecurityContext->DesiredAccess,
pIrp->RequestorMode,
GET_PP_FILTER_PROCESS(pFileObject)
);
if (NT_SUCCESS(status))
{
ASSERT( GET_FILTER_PROCESS(pFileObject) != NULL );
MARK_VALID_FILTER_CHANNEL( pFileObject );
}
}
else if(pDeviceObject == g_pUlAppPoolDeviceObject )
{
//
// It's an app pool.
//
//
// Bind to the specified app pool.
//
if (!IS_NAMED_FILE_OBJECT(pFileObject))
{
ASSERT(pFileObject->FileName.Buffer == NULL);
pName = NULL;
nameLength = 0;
// Validate the creation disposition. We allow create only
// for unnamed app-pools.
if(createDisposition != FILE_CREATE)
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
UlTrace(OPEN_CLOSE, (
"UlCreate: opening an unnamed AppPool: %p\n",
pFileObject
));
}
else
{
if (pFileObject->FileName.Length > UL_MAX_APP_POOL_NAME_SIZE)
{
status = STATUS_OBJECT_NAME_INVALID;
goto complete;
}
// Skip the preceding '\' in the FileName added by iomgr.
//
ASSERT(L'\\' == pFileObject->FileName.Buffer[0]);
pName = pFileObject->FileName.Buffer + 1;
nameLength = pFileObject->FileName.Length - sizeof(WCHAR);
pSafeName = UL_ALLOCATE_POOL(
PagedPool,
nameLength + sizeof(WCHAR),
UL_STRING_LOG_BUFFER_POOL_TAG
);
if(pSafeName == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto complete;
}
RtlCopyMemory(pSafeName, pName, nameLength);
pSafeName[nameLength/sizeof(WCHAR)] = L'\0';
pName = pSafeName;
if(createDisposition == FILE_CREATE)
{
//
// Creation of named app-pools must be only for admins.
//
// The filter object is has FileAll for Admin/LocalSystem only
// so, we'll piggy back on that security descriptor.
//
status = UlAccessCheck(
g_pAdminAllSystemAll,
pSecurityContext->AccessState,
pSecurityContext->DesiredAccess,
pIrp->RequestorMode,
pName
);
if(!NT_SUCCESS(status))
{
goto complete;
}
}
else if(createDisposition == FILE_OPEN)
{
// UlAttachProcessToAppPool will do the appropriate checks
// to ensure that the security descriptors match.
}
else
{
// Neither FILE_CREATE nor FILE_OPEN.
status = STATUS_INVALID_PARAMETER;
goto complete;
}
UlTrace(OPEN_CLOSE, (
"UlCreate: opening an AppPool: %p, %.*ls\n",
pFileObject, nameLength / sizeof(WCHAR), pName
));
}
status = UlAttachProcessToAppPool(
pName,
nameLength,
(BOOLEAN)(createDisposition == FILE_CREATE),
pSecurityContext->AccessState,
pSecurityContext->DesiredAccess,
pIrp->RequestorMode,
GET_PP_APP_POOL_PROCESS(pFileObject)
);
if (NT_SUCCESS(status))
{
ASSERT( GET_APP_POOL_PROCESS(pFileObject) != NULL );
MARK_VALID_APP_POOL( pFileObject );
}
}
else
{
ASSERT(pDeviceObject == g_pUcServerDeviceObject );
ASSERT(g_HttpClientEnabled);
//
// It is mandatory for the application to pass in a valid version
// and a valid URI. If either of this is missing, we bail.
//
//
if(pOpenPacket->ServerNameLength == 0 ||
pOpenPacket->pServerName == NULL ||
pOpenPacket->pTransportAddress == NULL ||
pOpenPacket->TransportAddressLength == 0 ||
IS_NAMED_FILE_OBJECT(pFileObject)
)
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
if(createDisposition != FILE_CREATE)
{
status = STATUS_INVALID_PARAMETER;
goto complete;
}
UlTrace(OPEN_CLOSE, (
"UlCreate: opening a ServInfo: %p\n",
pFileObject
));
//
// Create our context here and store it in
// pIrpSp->FileObject->FsContext
//
status = UcCreateServerInformation(
(PUC_PROCESS_SERVER_INFORMATION *)
&pFileObject->FsContext,
pOpenPacket->pServerName,
pOpenPacket->ServerNameLength,
pOpenPacket->pProxyName,
pOpenPacket->ProxyNameLength,
pOpenPacket->pTransportAddress,
pOpenPacket->TransportAddressLength,
pIrp->RequestorMode
);
//
// UC_BUGBUG (INVESTIGATE)
//
// Setting this field to non-NULL value enable fast IO code path
// for reads and writes.
//
// pIrpSp->FileObject->PrivateCacheMap = (PVOID)-1;
MARK_VALID_SERVER( pFileObject );
}
//
// Complete the request.
//
complete:
if(pSafeName)
{
ASSERT(pSafeName == pName);
UL_FREE_POOL(pSafeName, UL_STRING_LOG_BUFFER_POOL_TAG);
}
UlTrace(OPEN_CLOSE, (
"UlCreate: %s file object = %p, %s\n",
(NT_SUCCESS(status) ? "opened" : "did not open"),
pFileObject,
HttpStatusToString(status)
));
pIrp->IoStatus.Status = status;
UlCompleteRequest( pIrp, IO_NO_INCREMENT );
UL_LEAVE_DRIVER( "UlCreate" );
RETURN(status);
} // UlCreate