/*++ Copyright (c) 1999 Microsoft Corporation Module Name: netroot.c Abstract: This module implements the routines for creating net roots for the WebDav miniredir. Author: Rohan Kumar [RohanK] 24-April-1999 Revision History: --*/ #include "precomp.h" #pragma hdrstop #include "webdav.h" // // Mentioned below are the prototypes of functions tht are used only within // this module (file). These functions should not be exposed outside. // NTSTATUS MRxDAVCreateVNetRootContinuation( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE ); NTSTATUS MRxDAVFormatUserModeVNetRootCreateRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, PULONG_PTR ReturnedLength ); BOOL MRxDAVPrecompleteUserModeVNetRootCreateRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, BOOL OperationCancelled ); NTSTATUS MRxDAVFinalizeVNetRootContinuation( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE ); NTSTATUS MRxDAVFormatUserModeVNetRootFinalizeRequest( IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, IN ULONG WorkItemLength, OUT PULONG_PTR ReturnedLength ); BOOL MRxDAVPrecompleteUserModeVNetRootFinalizeRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, BOOL OperationCancelled ); NTSTATUS MRxDAVDereferenceNetRootContext( IN PWEBDAV_NET_ROOT DavNetRoot ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, MRxDAVUpdateNetRootState) #pragma alloc_text(PAGE, MRxDAVCreateVNetRoot) #pragma alloc_text(PAGE, MRxDAVCreateVNetRootContinuation) #pragma alloc_text(PAGE, MRxDAVFormatUserModeVNetRootCreateRequest) #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeVNetRootCreateRequest) #pragma alloc_text(PAGE, MRxDAVFinalizeNetRoot) #pragma alloc_text(PAGE, MRxDAVExtractNetRootName) #pragma alloc_text(PAGE, MRxDAVFinalizeVNetRoot) #pragma alloc_text(PAGE, MRxDAVFinalizeVNetRootContinuation) #pragma alloc_text(PAGE, MRxDAVFormatUserModeVNetRootFinalizeRequest) #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeVNetRootFinalizeRequest) #pragma alloc_text(PAGE, MRxDAVDereferenceNetRootContext) #endif // // Implementation of functions begins here. // NTSTATUS MRxDAVUpdateNetRootState( IN OUT PMRX_NET_ROOT pNetRoot ) /*++ Routine Description: This routine update the mini redirector state associated with a net root. Arguments: pNetRoot - the net root instance. Return Value: RXSTATUS - The return status for the operation Notes: --*/ { PAGED_CODE(); if (pNetRoot->Context == NULL) { pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR; } else { pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD; } return STATUS_SUCCESS; } NTSTATUS MRxDAVCreateVNetRoot( IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext ) /*++ Routine Description: This routine patches the RDBSS created net root instance with the information required by the mini redirector. Arguments: pCreateNetRootContext - the net root context for calling back Return Value: RXSTATUS - The return status for the operation Notes: --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PRX_CONTEXT RxContext = NULL; PMRX_V_NET_ROOT pVNetRoot = NULL; PWEBDAV_V_NET_ROOT DavVNetRoot = NULL; PWEBDAV_DEVICE_OBJECT DavDeviceObject = NULL; PUMRX_DEVICE_OBJECT UMRxDeviceObject = NULL; PMRX_SRV_CALL pSrvCall = NULL; PMRX_NET_ROOT pNetRoot = NULL; BOOLEAN SynchronousIo = FALSE; NTSTATUS ExNtStatus = STATUS_SUCCESS; HANDLE ExDeviceHandle = INVALID_HANDLE_VALUE; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING ExDeviceName; IO_STATUS_BLOCK IoStatusBlock; PKEY_VALUE_PARTIAL_INFORMATION DavKeyValuePartialInfo = NULL; PIO_STACK_LOCATION IrpSp = NULL; PFILE_OBJECT DavFileObject = NULL; PWCHAR NewFileName = NULL; ULONG NewFileNameLength = 0; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVCreateVNetRoot\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVCreateVNetRoot: pVNetRoot = %08lx\n", PsGetCurrentThreadId(), pVNetRoot)); RxContext = pCreateNetRootContext->RxContext; pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot; DavDeviceObject = (PWEBDAV_DEVICE_OBJECT)(RxContext->RxDeviceObject); UMRxDeviceObject = (PUMRX_DEVICE_OBJECT)&(DavDeviceObject->UMRefDeviceObject); pNetRoot = pVNetRoot->pNetRoot; pSrvCall = pNetRoot->pSrvCall; DavVNetRoot = MRxDAVGetVNetRootExtension(pVNetRoot); ASSERT(DavVNetRoot != NULL); ASSERT(NodeType(pNetRoot) == RDBSS_NTC_NETROOT); ASSERT(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVCreateVNetRoot: NetRootName = %wZ\n", PsGetCurrentThreadId(), pVNetRoot->pNetRoot->pNetRootName)); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVCreateVNetRoot: VNetRoot = %08lx\n", PsGetCurrentThreadId(), pVNetRoot)); // // Copy the LogonID in the MiniRedir's portion of the V_NET_ROOT. // DavVNetRoot->LogonID.LowPart = pVNetRoot->LogonId.LowPart; DavVNetRoot->LogonID.HighPart = pVNetRoot->LogonId.HighPart; DavVNetRoot->LogonIDSet = TRUE; DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVCreateVNetRoot: LogonID.LowPart = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot->LogonID.LowPart)); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVCreateVNetRoot: LogonID.HighPart = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot->LogonID.HighPart)); // // There are cases when we fail, we want the error which SMB returned to be // returned to the user. This is becuase SMB could have returned a more // specific error like logon failure or something on the share where as we // return share not found. To enable this we return STATUS_BAD_NETWORK_PATH // when the creation of netroot fails instead of STATUS_BAD_NETWORK_NAME // because MUP will overwrite SMBs error with our error if we return // STATUS_BAD_NETWORK_NAME. STATUS_BAD_NETWORK_NAME is a specif error which // implies that the share does not exist where as STATUS_BAD_NETWORK_PATH is // a more general error. // // // If the share name is a net root or a pipe, we reject it since SMB // Mini-Redir is the only one that handles it. // if ( pNetRoot->Type == NET_ROOT_PIPE || pNetRoot->Type == NET_ROOT_MAILSLOT ) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVCreateVNetRoot: Invalid NetRootType\n", PsGetCurrentThreadId())); // // We set the following flag in the DavVNetRoot structure to TRUE. This // is because when the finalize comes, we don't need to go to the // usermode. // DavVNetRoot->createVNetRootUnSuccessful = TRUE; pCreateNetRootContext->VirtualNetRootStatus = STATUS_BAD_NETWORK_PATH; // pCreateNetRootContext->VirtualNetRootStatus = STATUS_BAD_NETWORK_NAME; pCreateNetRootContext->NetRootStatus = STATUS_BAD_NETWORK_PATH; // pCreateNetRootContext->NetRootStatus = STATUS_BAD_NETWORK_NAME; goto EXIT_THE_FUNCTION; } SynchronousIo = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVCreateVNetRoot: SynchronousIo = %d\n", PsGetCurrentThreadId(), SynchronousIo)); // // We need to pass the server and share names to the user mode to check // whether they actually exist. RxContext has 4 pointers that the mini-redirs // can use. Here we use MRxContext[1]. We store a reference to the pVNetRoot // strucutre. MRxContext[0] is used to store a reference to the // AsynEngineContext and this is done when the context gets created in the // function UMRxCreateAsyncEngineContext. // RxContext->MRxContext[1] = pVNetRoot; // // We now need to go to the user mode and find out if this WebDav share // exists on the server. // NtStatus = UMRxAsyncEngOuterWrapper(RxContext, SIZEOF_DAV_SPECIFIC_CONTEXT, MRxDAVFormatTheDAVContext, DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT, MRxDAVCreateVNetRootContinuation, "MRxDAVCreateVNetRoot"); if (NtStatus != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVCreateVNetRoot/UMRxAsyncEngOuterWrapper: " "NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus)); if (NtStatus == STATUS_ACCESS_DENIED || NtStatus == STATUS_LOGON_FAILURE || NtStatus == STATUS_NETWORK_CREDENTIAL_CONFLICT) { pCreateNetRootContext->VirtualNetRootStatus = NtStatus; } else { pCreateNetRootContext->VirtualNetRootStatus = STATUS_BAD_NETWORK_PATH; } // // Don't set the NetRootStatus here since it is a global data structure // shared among different VNetRoots (TS users). Failure on one VNetRoot // should not affects the NetRoot. // goto EXIT_THE_FUNCTION; } // // If we succeeded and the share is not a TAHOE share, nor an Office Web // Server share, then we claim the share name. Otherwise we fail since the // users intends to use the TAHOE specific features in Rosebud, or Office // specific features in Shell. // if ( !DavVNetRoot->isTahoeShare && !DavVNetRoot->isOfficeShare ) { pNetRoot->DeviceType = RxDeviceType(DISK); pNetRoot->Type = NET_ROOT_DISK; pCreateNetRootContext->VirtualNetRootStatus = STATUS_SUCCESS; pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS; } else { DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVCreateVNetRoot/UMRxAsyncEngOuterWrapper: " "TAHOE or OFFICE Share\n", PsGetCurrentThreadId())); pCreateNetRootContext->VirtualNetRootStatus = STATUS_BAD_NETWORK_PATH; // pCreateNetRootContext->VirtualNetRootStatus = STATUS_BAD_NETWORK_NAME; pCreateNetRootContext->NetRootStatus = STATUS_BAD_NETWORK_PATH; // pCreateNetRootContext->NetRootStatus = STATUS_BAD_NETWORK_NAME; } if (pNetRoot->Context == NULL) { pNetRoot->Context = RxAllocatePoolWithTag(PagedPool, sizeof(WEBDAV_NET_ROOT), DAV_NETROOT_POOLTAG); if (pNetRoot->Context == NULL) { pCreateNetRootContext->VirtualNetRootStatus = STATUS_INSUFFICIENT_RESOURCES; pCreateNetRootContext->NetRootStatus = STATUS_INSUFFICIENT_RESOURCES; } else { PWEBDAV_NET_ROOT DavNetRoot = (PWEBDAV_NET_ROOT)pNetRoot->Context; // // Refcount of 2, one is taken away at VNetRoot finalization, another one is taken // away at NetRoot finalization. // DavNetRoot->RefCount = 2; DavNetRoot->pRdbssNetRoot = pNetRoot; RxNameCacheInitialize(&DavNetRoot->NameCacheCtlGFABasic, sizeof(FILE_BASIC_INFORMATION), NameCacheMaxEntries); RxNameCacheInitialize(&DavNetRoot->NameCacheCtlGFAStandard, sizeof(FILE_STANDARD_INFORMATION), NameCacheMaxEntries); RxNameCacheInitialize(&DavNetRoot->NameCacheCtlFNF, 0, NameCacheMaxEntries); pVNetRoot->Context2 = DavNetRoot; DavDbgTrace(DAV_TRACE_DAVNETROOT, ("MRxDav allocates DavNetRoot %x %x %x 2\n",DavNetRoot,pNetRoot,pVNetRoot)); } } else { PWEBDAV_NET_ROOT DavNetRoot = (PWEBDAV_NET_ROOT)pNetRoot->Context; pVNetRoot->Context2 = DavNetRoot; InterlockedIncrement(&DavNetRoot->RefCount); DavDbgTrace(DAV_TRACE_DAVNETROOT, ("MRxDAVCreateVNetRoot ref DavNetRoot %x %x %x %d\n",DavNetRoot,pNetRoot,pVNetRoot,DavNetRoot->RefCount)); } // // We return from here since the code below was written for accomodating the // exchange DAV Redir which was suppose to ship with Office 2000. Since that // project (LocalStore which included the Exchange Redir) has been canned, // (as of Dec 8th, 2000) we don't need to execute the code below any more. // We will keep it around though, just in case. // goto EXIT_THE_FUNCTION; // // The Exchange Redir has been installed on the system. Now we need to find // out if its loaded. This is an exchange share. If the exchange Redir is // not installed, we claim the name. // DavKeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DavExchangeDeviceName; RtlInitUnicodeString( &(ExDeviceName), (PWCHAR)DavKeyValuePartialInfo->Data ); InitializeObjectAttributes(&(ObjectAttributes), &(ExDeviceName), OBJ_CASE_INSENSITIVE, 0, NULL); ExNtStatus = NtOpenFile(&(ExDeviceHandle), 0, &(ObjectAttributes), &(IoStatusBlock), 0, 0); if (ExNtStatus != STATUS_SUCCESS) { // // This is an exchange share but the Exchange Redir is not installed. // We will handle this. // ExDeviceHandle = INVALID_HANDLE_VALUE; DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVCreateVNetRoot. Exchange BUT No Redir\n", PsGetCurrentThreadId())); pNetRoot->DeviceType = RxDeviceType(DISK); pNetRoot->Type = NET_ROOT_DISK; pCreateNetRootContext->VirtualNetRootStatus = STATUS_SUCCESS; pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS; goto EXIT_THE_FUNCTION; } IrpSp = IoGetCurrentIrpStackLocation(RxContext->CurrentIrp); DavFileObject = IrpSp->FileObject; // // The NewFileNameLength is = ExchangeDeviceNameLength + PathName. The // DavKeyValuePartialInfo->DataLength contains an extra 2 bytes for the // \0 char. // NewFileNameLength = ( DavKeyValuePartialInfo->DataLength + DavFileObject->FileName.Length ); // // If the first char is not a \, then we need to add another sizeof(WCHAR). // if (DavFileObject->FileName.Buffer[0] != L'\\') { NewFileNameLength += sizeof(WCHAR); } // // Allocate memory for the NewFileName. // NewFileName = ExAllocatePoolWithTag(PagedPool, NewFileNameLength, DAV_EXCHANGE_POOLTAG); if (NewFileName == NULL) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVCreateVNetRoot/ExAllocatePoolWithTag\n", PsGetCurrentThreadId())); pCreateNetRootContext->VirtualNetRootStatus = STATUS_INSUFFICIENT_RESOURCES; pCreateNetRootContext->NetRootStatus = STATUS_INSUFFICIENT_RESOURCES; goto EXIT_THE_FUNCTION; } RtlZeroMemory(NewFileName, NewFileNameLength); // // Copy the new device name. // RtlCopyMemory(NewFileName, DavKeyValuePartialInfo->Data, DavKeyValuePartialInfo->DataLength); // // If the first char is not a \, then we need to copy it before we copy the // rest of the name. // if (DavFileObject->FileName.Buffer[0] != L'\\') { // // Copy the \ next. // RtlCopyMemory( ( NewFileName + DavKeyValuePartialInfo->DataLength ), L"\\", sizeof(WCHAR) ); // // Finally copy the PathName that was sent with this IRP. // RtlCopyMemory( ( NewFileName + DavKeyValuePartialInfo->DataLength + sizeof(WCHAR) ), DavFileObject->FileName.Buffer, DavFileObject->FileName.Length ); } else { // // Finally copy the PathName that was sent with this IRP. // RtlCopyMemory( ( NewFileName + DavKeyValuePartialInfo->DataLength ), DavFileObject->FileName.Buffer, DavFileObject->FileName.Length ); } // // Free the memory allocated in the FileObject's original filename buffer. // ExFreePool(DavFileObject->FileName.Buffer); // // Set the NewFileName in the FileObject. // DavFileObject->FileName.Buffer = NewFileName; DavFileObject->FileName.Length = (USHORT)NewFileNameLength; DavFileObject->FileName.MaximumLength = (USHORT)NewFileNameLength; // // Finally, set the status to STATUS_REPARSE so that the I/O manager will // call into the Exchange Redir. // pCreateNetRootContext->VirtualNetRootStatus = STATUS_REPARSE; pCreateNetRootContext->NetRootStatus = STATUS_REPARSE; EXIT_THE_FUNCTION: // // Callback the RDBSS for resumption. // pCreateNetRootContext->Callback(pCreateNetRootContext); // // If we opened a handle to the exchange redir, we need to close it now. // if (ExDeviceHandle != INVALID_HANDLE_VALUE) { NtClose(ExDeviceHandle); } // // Map the error code to STATUS_PENDING since this triggers the // synchronization mechanism in the RDBSS. // DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVCreateVNetRoot\n", PsGetCurrentThreadId())); return STATUS_PENDING; } NTSTATUS MRxDAVCreateVNetRootContinuation( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE ) /*++ Routine Description: This routine checks to see if the share for which a VNetRoot is being created exists or not. Arguments: AsyncEngineContext - The Reflectors context. RxContext - The RDBSS context. Return Value: RXSTATUS - The return status for the operation. --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVCreateVNetRootContinuation\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVCreateVNetRootContinuation: " "AsyncEngineContext: %08lx, RxContext: %08lx\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); // // Try usermode. // NtStatus = UMRxSubmitAsyncEngUserModeRequest( UMRX_ASYNCENGINE_ARGUMENTS, MRxDAVFormatUserModeVNetRootCreateRequest, MRxDAVPrecompleteUserModeVNetRootCreateRequest ); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVCreateVNetRootContinuation with NtStatus =" " %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } NTSTATUS MRxDAVFormatUserModeVNetRootCreateRequest( IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, IN ULONG WorkItemLength, OUT PULONG_PTR ReturnedLength ) /*++ Routine Description: This routine formats the VNetRoot create request being sent to the user mode for processing. Arguments: RxContext - The RDBSS context. AsyncEngineContext - The reflctor's context. WorkItem - The work item buffer. WorkItemLength - The length of the work item buffer. ReturnedLength - Return Value: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES. --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PDAV_USERMODE_WORKITEM WorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader; PMRX_SRV_CALL SrvCall = NULL; PWEBDAV_SRV_CALL DavSrvCall = NULL; PMRX_NET_ROOT NetRoot = NULL; PMRX_V_NET_ROOT VNetRoot = NULL; PWEBDAV_V_NET_ROOT DavVNetRoot = NULL; PSECURITY_CLIENT_CONTEXT SecurityClientContext = NULL; PDAV_USERMODE_CREATE_V_NET_ROOT_REQUEST CreateVNetRootRequest = NULL; PWCHAR ServerName = NULL, ShareName = NULL; PWCHAR NetRootName = NULL, JustTheNetRootName = NULL; ULONG ServerNameLengthInBytes = 0, NetRootNameLengthInBytes = 0; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVFormatUserModeVNetRootCreateRequest!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVFormatUserModeVNetRootCreateRequest: AsyncEngineContext" " = %08lx, RxContext = %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); CreateVNetRootRequest = &(WorkItem->CreateVNetRootRequest); // // We need to set the work item type. // WorkItem->WorkItemType = UserModeCreateVNetRoot; // // The VNetRoot pointer is stored in the MRxContext[1] pointer of the // RxContext structure. This is done in the MRxDAVCreateVNetRoot function. // VNetRoot = (PMRX_V_NET_ROOT)RxContext->MRxContext[1]; ASSERT(VNetRoot != NULL); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVFormatUserModeVNetRootCreateRequest: " "VNetRoot = %08lx\n", PsGetCurrentThreadId(), VNetRoot)); DavVNetRoot = MRxDAVGetVNetRootExtension(VNetRoot); ASSERT(DavVNetRoot != NULL); NetRoot = VNetRoot->pNetRoot; ASSERT(NetRoot != NULL); SrvCall = NetRoot->pSrvCall; ASSERT(SrvCall != NULL); DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall); ASSERT(DavSrvCall != NULL); SecurityClientContext = &(DavVNetRoot->SecurityClientContext); // // Copy the LogonID in the CreateRequest buffer. The LogonId is in the // MiniRedir's portion of the V_NET_ROOT. // CreateVNetRootRequest->LogonID.LowPart = DavVNetRoot->LogonID.LowPart; CreateVNetRootRequest->LogonID.HighPart = DavVNetRoot->LogonID.HighPart; DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVFormatUserModeVNetRootCreateRequest: LogonID.LowPart = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot->LogonID.LowPart)); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVFormatUserModeVNetRootCreateRequest: LogonID.HighPart = %08lx\n", PsGetCurrentThreadId(), DavVNetRoot->LogonID.HighPart)); // // Copy the ServerName. // ServerNameLengthInBytes = ( SrvCall->pSrvCallName->Length + sizeof(WCHAR) ); ServerName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext, ServerNameLengthInBytes); if (ServerName == NULL) { NtStatus = STATUS_INSUFFICIENT_RESOURCES; DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVFormatUserModeVNetRootCreateRequest/" "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } RtlCopyBytes(ServerName, SrvCall->pSrvCallName->Buffer, SrvCall->pSrvCallName->Length); ServerName[( ( (ServerNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0'; CreateVNetRootRequest->ServerName = ServerName; DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVFormatUserModeVNetRootCreateRequest: ServerName: " "%ws\n", PsGetCurrentThreadId(), ServerName)); // // Copy the ServerID. // CreateVNetRootRequest->ServerID = DavSrvCall->ServerID; // // The NetRootName (pNetRootName) includes the ServerName. Hence to get the // NetRootNameLengthInBytes, we do the following. // NetRootNameLengthInBytes = (NetRoot->pNetRootName->Length - SrvCall->pSrvCallName->Length); // // For '\0' at the end. // NetRootNameLengthInBytes += sizeof(WCHAR); NetRootName = &(NetRoot->pNetRootName->Buffer[1]); JustTheNetRootName = wcschr(NetRootName, L'\\'); // // Copy the NetRoot (Share) name. // ShareName = (PWCHAR) UMRxAllocateSecondaryBuffer(AsyncEngineContext, NetRootNameLengthInBytes); if (ShareName == NULL) { NtStatus = STATUS_INSUFFICIENT_RESOURCES; DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVFormatUserModeVNetRootCreateRequest/" "UMRxAllocateSecondaryBuffer. NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } RtlCopyBytes(ShareName, JustTheNetRootName, (NetRoot->pNetRootName->Length - SrvCall->pSrvCallName->Length)); ShareName[( ( (NetRootNameLengthInBytes) / sizeof(WCHAR) ) - 1 )] = L'\0'; CreateVNetRootRequest->ShareName = ShareName; DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVFormatUserModeVNetRootCreateRequest: ShareName: " "%ws\n", PsGetCurrentThreadId(), ShareName)); // // Impersonate the client who initiated the request. If we fail to // impersonate, tough luck. // if (SecurityClientContext != NULL) { NtStatus = UMRxImpersonateClient(SecurityClientContext, WorkItemHeader); if (!NT_SUCCESS(NtStatus)) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVFormatUserModeVNetRootCreateRequest/" "UMRxImpersonateClient. NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } } else { NtStatus = STATUS_INVALID_PARAMETER; DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVFormatUserModeVNetRootCreateRequest: " "SecurityClientContext is NULL.\n", PsGetCurrentThreadId())); goto EXIT_THE_FUNCTION; } ASSERT(WorkItem->UserName[0] == L'\0' && WorkItem->Password[0] == L'\0'); if (VNetRoot->pUserName && VNetRoot->pUserName->Length) { RtlCopyMemory(WorkItem->UserName,VNetRoot->pUserName->Buffer,VNetRoot->pUserName->Length); } if (VNetRoot->pPassword && VNetRoot->pPassword->Length) { RtlCopyMemory(WorkItem->Password,VNetRoot->pPassword->Buffer,VNetRoot->pPassword->Length); } EXIT_THE_FUNCTION: DavDbgTrace(DAV_TRACE_ENTRYEXIT, ("%ld: Leaving MRxDAVFormatUserModeVNetRootCreateRequest with " "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } BOOL MRxDAVPrecompleteUserModeVNetRootCreateRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, BOOL OperationCancelled ) /*++ Routine Description: The precompletion routine for the CreateVNetRoot request. Arguments: RxContext - The RDBSS context. AsyncEngineContext - The reflctor's context. WorkItem - The work item buffer. WorkItemLength - The length of the work item buffer. OperationCancelled - TRUE if this operation was cancelled by the user. Return Value: TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function UMRxCompleteUserModeRequest after we return. --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PDAV_USERMODE_CREATE_V_NET_ROOT_REQUEST CreateVNetRootRequest = NULL; PDAV_USERMODE_CREATE_V_NET_ROOT_RESPONSE CreateVNetRootResponse = NULL; PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader; PWEBDAV_V_NET_ROOT DavVNetRoot = NULL; PMRX_V_NET_ROOT VNetRoot = NULL; PAGED_CODE(); CreateVNetRootRequest = &(DavWorkItem->CreateVNetRootRequest); CreateVNetRootResponse = &(DavWorkItem->CreateVNetRootResponse); if (!OperationCancelled) { // // The VNetRoot pointer is stored in the MRxContext[1] pointer of the // RxContext structure. This is done in the MRxDAVCreateVNetRoot // function. // VNetRoot = (PMRX_V_NET_ROOT)RxContext->MRxContext[1]; DavVNetRoot = MRxDAVGetVNetRootExtension(VNetRoot); ASSERT(DavVNetRoot != NULL); } else { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: MRxDAVPrecompleteUserModeVNetRootCreateRequest: Operation Cancelled. " "AsyncEngineContext = %08lx, RxContext = %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); } // // We need to free up the heaps, we allocated in the format routine. // if (CreateVNetRootRequest->ServerName != NULL) { NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext, (PBYTE)CreateVNetRootRequest->ServerName); if (NtStatus != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVPrecompleteUserModeVNetRootCreateRequest/" "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } } if (CreateVNetRootRequest->ShareName != NULL) { NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext, (PBYTE)CreateVNetRootRequest->ShareName); if (NtStatus != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVPrecompleteUserModeVNetRootCreateRequest/" "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } } if (!OperationCancelled) { NtStatus = AsyncEngineContext->Status; if (NtStatus != STATUS_SUCCESS) { // // If the CreateVNetRoot failed in the usermode, we set the following // in the DavVNetRoot structure to TRUE. This is because when the // finalize comes, we don't need to go to the usermode. // DavVNetRoot->createVNetRootUnSuccessful = TRUE; DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVPrecompleteUserModeVNetRootCreateRequest:" " NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); } else { // // We would have figured out in the usermode if this share is a TAHOE // share or an Office Web Server share and whether this share allows // PROPPATCH or not, and resporst available space or not // DavVNetRoot->isOfficeShare = CreateVNetRootResponse->isOfficeShare; DavVNetRoot->isTahoeShare = CreateVNetRootResponse->isTahoeShare; DavVNetRoot->fAllowsProppatch = CreateVNetRootResponse->fAllowsProppatch; DavVNetRoot->fReportsAvailableSpace = CreateVNetRootResponse->fReportsAvailableSpace; } } EXIT_THE_FUNCTION: return(TRUE); } NTSTATUS MRxDAVDereferenceNetRootContext( IN PWEBDAV_NET_ROOT DavNetRoot ) /*++ Routine Description: This routine dereferences the Webdav NetRoot instance and free it if the refcount reaches 0. Arguments: DavNetRoot - The Webdav NetRoot. Return Value: STATUS_SUCCESS --*/ { PAGED_CODE(); if (DavNetRoot != NULL) { ULONG RefCount; RefCount = InterlockedDecrement(&DavNetRoot->RefCount); DavDbgTrace(DAV_TRACE_DAVNETROOT, ("MRxDAVDereferenceNetRootContext %x %d\n",DavNetRoot,RefCount)); if (RefCount == 0) { // // Free storage associated with all entries in the name caches. // RxNameCacheFinalize(&DavNetRoot->NameCacheCtlGFABasic); RxNameCacheFinalize(&DavNetRoot->NameCacheCtlGFAStandard); RxNameCacheFinalize(&DavNetRoot->NameCacheCtlFNF); // // Reset the Context so that no further reference can be made to this DavNetRoot // ASSERT(DavNetRoot->pRdbssNetRoot->Context == DavNetRoot); DavNetRoot->pRdbssNetRoot->Context = NULL; RxFreePool(DavNetRoot); DavDbgTrace(DAV_TRACE_DAVNETROOT, ("MRxDav frees DavNetRoot %x\n",DavNetRoot)); } } return STATUS_SUCCESS; } NTSTATUS MRxDAVFinalizeNetRoot( IN PMRX_NET_ROOT pNetRoot, IN PBOOLEAN ForceDisconnect ) /*++ Routine Description: Arguments: pVirtualNetRoot - The Virtual NetRoot. ForceDisconnect - Disconnect is forced. Return Value: RXSTATUS - The return status for the operation --*/ { PWEBDAV_NET_ROOT DavNetRoot = (PWEBDAV_NET_ROOT)pNetRoot->Context; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering UMRxFinalizeNetRoot!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: UMRxFinalizeNetRoot: pNetRoot = %08lx.\n", PsGetCurrentThreadId(), pNetRoot)); DavDbgTrace(DAV_TRACE_DAVNETROOT, ("MRxDAVFinalizeNetRoot deref DavNetRoot %x %x\n",pNetRoot->Context,pNetRoot)); MRxDAVDereferenceNetRootContext((PWEBDAV_NET_ROOT)pNetRoot->Context); return STATUS_SUCCESS; } VOID MRxDAVExtractNetRootName( IN PUNICODE_STRING FilePathName, IN PMRX_SRV_CALL SrvCall, OUT PUNICODE_STRING NetRootName, OUT PUNICODE_STRING RestOfName OPTIONAL ) /*++ Routine Description: This routine parses the input name into srv, netroot, and the rest. Arguments: FilePathName - The filename that came in. SrvCall - The SrvCall strucutre created by RDBSS. NetRootName - Pointer to the netroot name. RestOfName - Pointer to the Rest of the name. Return Value: none. --*/ { UNICODE_STRING xRestOfName; ULONG length = FilePathName->Length; PWCH w = FilePathName->Buffer; PWCH wlimit = (PWCH)(((PCHAR)w) + length); PWCH wlow; PAGED_CODE(); // // The netroot name starts after the SrvCall name. // w += (SrvCall->pSrvCallName->Length/sizeof(WCHAR)); NetRootName->Buffer = wlow = w; // // Calculate the length of the NetRoot name. // for ( ; ; ) { if (w >= wlimit) break; if ( (*w == OBJ_NAME_PATH_SEPARATOR) && (w != wlow) ){ #if ZZZ_MODE if (*(w - 1) == L'z') { w++; continue; } #endif // if ZZZ_MODE break; } w++; } NetRootName->Length = NetRootName->MaximumLength = (USHORT)((PCHAR)w - (PCHAR)wlow); if (!RestOfName) { RestOfName = &xRestOfName; } RestOfName->Buffer = w; RestOfName->Length = RestOfName->MaximumLength = (USHORT)((PCHAR)wlimit - (PCHAR)w); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVExtractNetRootName: FilePath = %wZ\n", PsGetCurrentThreadId(), FilePathName)); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVExtractNetRootName: Srv = %wZ, Root = %wZ, " "Rest = %wZ\n", PsGetCurrentThreadId(), SrvCall->pSrvCallName, NetRootName, RestOfName)); return; } NTSTATUS MRxDAVFinalizeVNetRoot( IN PMRX_V_NET_ROOT pVNetRoot, IN PBOOLEAN ForceDisconnect ) /*++ Routine Description: Arguments: pVNetRoot - The virtual net root which has to be finalized. ForceDisconnect - Disconnect is forced. Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PRX_CONTEXT RxContext = NULL; PMRX_SRV_CALL SrvCall = NULL; PRDBSS_DEVICE_OBJECT RxDeviceObject = NULL; PWEBDAV_V_NET_ROOT DavVNetRoot = NULL; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering UMRxFinalizeVNetRoot!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: UMRxFinalizeVNetRoot: NetRootName = %wZ\n", PsGetCurrentThreadId(), pVNetRoot->pNetRoot->pNetRootName)); SrvCall = pVNetRoot->pNetRoot->pSrvCall; RxDeviceObject = SrvCall->RxDeviceObject; DavVNetRoot = MRxDAVGetVNetRootExtension(pVNetRoot); ASSERT(DavVNetRoot != NULL); // // If we created the SecurityClientContext, we need to delete it now. We // don't need this when we go up to the usermode to finalize the VNetRoot // since we don't impersonate the client when doing this. // if (DavVNetRoot->SCAlreadyInitialized) { SeDeleteClientSecurity(&(DavVNetRoot->SecurityClientContext)); } DavDbgTrace(DAV_TRACE_DAVNETROOT, ("MRxDAVFinalizeVNetRoot deref DavNetRoot %x %x %x\n",pVNetRoot->Context2,pVNetRoot->pNetRoot,pVNetRoot)); MRxDAVDereferenceNetRootContext((PWEBDAV_NET_ROOT)pVNetRoot->Context2); pVNetRoot->Context2 = NULL; // // We need to make sure that the creation of this VNetRoot was successful. // If it was not, then we don't go to the usermode to finalize the // PerUserEntry. Also, if the MiniRedir never got called during the // creation of VNetRoot (possible in some failure case) then we should not // go to the user mode. If the MiniRedir never gets called LogonIDSet will // be FALSE. If the MiniRedir gets called this will be TRUE for sure. // if (DavVNetRoot->createVNetRootUnSuccessful || !DavVNetRoot->LogonIDSet) { DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: UMRxFinalizeVNetRoot. createVNetRootUnSuccessful\n", PsGetCurrentThreadId())); goto EXIT_THE_FUNCTION; } // // Unfortunately, we do not have an RxContext here and hence have to create // one. An RxContext is required for a request to be reflected up. // RxContext = RxCreateRxContext(NULL, RxDeviceObject, 0); if (RxContext == NULL) { NtStatus = STATUS_INSUFFICIENT_RESOURCES; DavDbgTrace(DAV_TRACE_ERROR, ("%ld: MRxDAVFinalizeVNetRoot/RxCreateRxContext: " "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } // // We need to send the VNetRoot to the format routine and use the // MRxContext[1] pointer of the RxContext structure to store it. // RxContext->MRxContext[1] = (PVOID)pVNetRoot; NtStatus = UMRxAsyncEngOuterWrapper(RxContext, SIZEOF_DAV_SPECIFIC_CONTEXT, MRxDAVFormatTheDAVContext, DAV_MINIRDR_ENTRY_FROM_FINALIZEVNETROOT, MRxDAVFinalizeVNetRootContinuation, "MRxDAVFinalizeVNetRoot"); if (NtStatus != ERROR_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: MRxDAVFinalizeVNetRoot/UMRxAsyncEngOuterWrapper: " "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); } EXIT_THE_FUNCTION: if (RxContext) { RxDereferenceAndDeleteRxContext(RxContext); } DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVFinalizeVNetRoot with NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } NTSTATUS MRxDAVFinalizeVNetRootContinuation( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE ) /*++ ORoutine Description: This is the continuation routine which finalizes a VNetRoot. Arguments: AsyncEngineContext - The Reflectors context. RxContext - The RDBSS context. Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVFinalizeVNetRootContinuation!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVFinalizeVNetRootContinuation: " "AsyncEngineContext: %08lx, RxContext: %08lx\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); // // Try usermode. // NtStatus = UMRxSubmitAsyncEngUserModeRequest( UMRX_ASYNCENGINE_ARGUMENTS, MRxDAVFormatUserModeVNetRootFinalizeRequest, MRxDAVPrecompleteUserModeVNetRootFinalizeRequest ); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVFinalizeVNetRootContinuation with NtStatus" " = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } NTSTATUS MRxDAVFormatUserModeVNetRootFinalizeRequest( IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, IN ULONG WorkItemLength, OUT PULONG_PTR ReturnedLength ) /*++ Routine Description: This routine formats the VNetRoot finalize request being sent to the user mode for processing. Arguments: RxContext - The RDBSS context. AsyncEngineContext - The reflctor's context. WorkItem - The work item buffer. WorkItemLength - The length of the work item buffer. ReturnedLength - Return Value: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES. --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader; PMRX_SRV_CALL SrvCall = NULL; PWEBDAV_SRV_CALL DavSrvCall = NULL; PMRX_V_NET_ROOT VNetRoot = NULL; PWEBDAV_V_NET_ROOT DavVNetRoot = NULL; PWCHAR ServerName = NULL; ULONG ServerNameLengthInBytes = 0; PBYTE SecondaryBuff = NULL; PDAV_USERMODE_FINALIZE_V_NET_ROOT_REQUEST DavFinalizeVNetRootRequest = NULL; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVFormatUserModeVNetRootFinalizeRequest\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVFormatUserModeVNetRootFinalizeRequest: " "AsyncEngineContext: %08lx, RxContext: %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); VNetRoot = (PMRX_V_NET_ROOT)RxContext->MRxContext[1]; ASSERT(VNetRoot != NULL); DavVNetRoot = MRxDAVGetVNetRootExtension(VNetRoot); ASSERT(DavVNetRoot != NULL); SrvCall = VNetRoot->pNetRoot->pSrvCall; ASSERT(SrvCall != NULL); DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall); ASSERT(DavSrvCall != NULL); DavWorkItem->WorkItemType = UserModeFinalizeVNetRoot; DavFinalizeVNetRootRequest = &(DavWorkItem->FinalizeVNetRootRequest); // // Set the ServerID. // DavFinalizeVNetRootRequest->ServerID = DavSrvCall->ServerID; // // Set the LogonID. // DavFinalizeVNetRootRequest->LogonID.LowPart = DavVNetRoot->LogonID.LowPart; DavFinalizeVNetRootRequest->LogonID.HighPart = DavVNetRoot->LogonID.HighPart; DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVFormatUserModeVNetRootFinalizeRequest: " "LogonID.LowPart = %d, LogonID.HighPart = %d\n", PsGetCurrentThreadId(), DavVNetRoot->LogonID.LowPart, DavVNetRoot->LogonID.HighPart)); // // Set the Server name. // ServerName = &(SrvCall->pSrvCallName->Buffer[1]); ServerNameLengthInBytes = (1 + wcslen(ServerName)) * sizeof(WCHAR); SecondaryBuff = UMRxAllocateSecondaryBuffer(AsyncEngineContext, ServerNameLengthInBytes); if (SecondaryBuff == NULL) { NtStatus = STATUS_INSUFFICIENT_RESOURCES; DavDbgTrace(DAV_TRACE_ERROR, ("ld: MRxDAVFormatUserModeVNetRootFinalizeRequest/" "UMRxAllocateSecondaryBuffer: ERROR: NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } DavFinalizeVNetRootRequest->ServerName = (PWCHAR)SecondaryBuff; wcscpy(DavFinalizeVNetRootRequest->ServerName, ServerName); EXIT_THE_FUNCTION: DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVFormatUserModeVNetRootFinalizeRequest " "with NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } BOOL MRxDAVPrecompleteUserModeVNetRootFinalizeRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, BOOL OperationCancelled ) /*++ Routine Description: The precompletion routine for the finalize VNetRoot request. Arguments: RxContext - The RDBSS context. AsyncEngineContext - The reflctor's context. WorkItem - The work item buffer. WorkItemLength - The length of the work item buffer. OperationCancelled - TRUE if this operation was cancelled by the user. Return Value: TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function UMRxCompleteUserModeRequest after we return. --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PDAV_USERMODE_WORKITEM WorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader; PDAV_USERMODE_FINALIZE_V_NET_ROOT_REQUEST DavFinalizeVNetRootRequest = NULL; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVPrecompleteUserModeVNetRootFinalizeRequest\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVPrecompleteUserModeVNetRootFinalizeRequest: " "AsyncEngineContext: %08lx, RxContext: %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); // // A FinalizeVNetRoot request can never by Async. // ASSERT(AsyncEngineContext->AsyncOperation == FALSE); // // If this operation was cancelled, then we don't need to do anything // special in the FinalizeVNetRoot case. // if (OperationCancelled) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: MRxDAVPrecompleteUserModeVNetRootFinalizeRequest: Operation Cancelled. " "AsyncEngineContext = %08lx, RxContext = %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); } DavFinalizeVNetRootRequest = &(WorkItem->FinalizeVNetRootRequest); // // We need to free up the heap we allocated in the format routine. // if (DavFinalizeVNetRootRequest->ServerName != NULL) { NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext, (PBYTE)DavFinalizeVNetRootRequest->ServerName); if (NtStatus != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVPrecompleteUserModeVNetRootFinalizeRequestt/" "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); } } if (AsyncEngineContext->Status != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVPrecompleteUserModeVNetRootFinalizeRequest. " "Finalize VNetRoot Failed!!!\n", PsGetCurrentThreadId())); } DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVPrecompleteUserModeVNetRootFinalizeRequest\n", PsGetCurrentThreadId())); return TRUE; }