/*++ Copyright (c) 1999 Microsoft Corporation Module Name: srvcall.c Abstract: This module implements the routines for handling the creation/manipulation of server entries in the connection engine database. Author: Balan Sethu Raman [SethuR] Rohan Kumar [RohanK] 04-April-1999 --*/ #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. // VOID MRxDAVSrvCallWrapper( PVOID Context ); NTSTATUS MRxDAVCreateSrvCallContinuation( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE ); NTSTATUS MRxDAVFormatUserModeSrvCallCreateRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, PULONG_PTR ReturnedLength ); BOOL MRxDAVPrecompleteUserModeSrvCallCreateRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, BOOL OperationCancelled ); NTSTATUS MRxDAVFinalizeSrvCallContinuation( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE ); NTSTATUS MRxDAVFormatUserModeSrvCallFinalizeRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, PULONG_PTR ReturnedLength ); BOOL MRxDAVPrecompleteUserModeSrvCallFinalizeRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, BOOL OperationCancelled ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, MRxDAVCreateSrvCall) #pragma alloc_text(PAGE, MRxDAVSrvCallWrapper) #pragma alloc_text(PAGE, MRxDAVCreateSrvCallContinuation) #pragma alloc_text(PAGE, MRxDAVFormatUserModeSrvCallCreateRequest) #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeSrvCallCreateRequest) #pragma alloc_text(PAGE, MRxDAVFinalizeSrvCall) #pragma alloc_text(PAGE, MRxDAVFinalizeSrvCallContinuation) #pragma alloc_text(PAGE, MRxDAVFormatUserModeSrvCallFinalizeRequest) #pragma alloc_text(PAGE, MRxDAVPrecompleteUserModeSrvCallFinalizeRequest) #pragma alloc_text(PAGE, MRxDAVSrvCallWinnerNotify) #endif // // Implementation of functions begins here. // NTSTATUS MRxDAVCreateSrvCall( PMRX_SRV_CALL SrvCall, PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext ) /*++ Routine Description: This routine handles the creation of SrvCalls. Arguments: SrvCall - CallBackContext - the call back context in RDBSS for continuation. Return Value: RXSTATUS - The return status for the operation Notes: --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = CallbackContext; PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = NULL; PRX_CONTEXT RxContext = NULL; PAGED_CODE(); #if 1 SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(CallbackContext->SrvCalldownStructure); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVCreateSrvCall!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVCreateSrvCall: SrvCall: %08lx, CallbackContext: " "%08lx.\n", PsGetCurrentThreadId(), SrvCall, CallbackContext)); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVCreateSrvCall: SrvCallName: %wZ\n", PsGetCurrentThreadId(), SrvCall->pSrvCallName)); // // Perform the following checks. // ASSERT(NodeType(SrvCall) == RDBSS_NTC_SRVCALL); ASSERT(SrvCall); ASSERT(SrvCall->pSrvCallName); ASSERT(SrvCall->pSrvCallName->Buffer); ASSERT(SCCBC->RxDeviceObject); // // Before delaying the final close, RDBSS looks at the number of closes that // have been delayed and compares it against this value. // SrvCall->MaximumNumberOfCloseDelayedFiles = 150; // // Allocate memory for the context pointer in the SrvCall structure. This is // for the Mini-Redirs use. // ASSERT(SrvCall->Context == NULL); SrvCall->Context = RxAllocatePoolWithTag(NonPagedPool, sizeof(WEBDAV_SRV_CALL), DAV_SRVCALL_POOLTAG); if (SrvCall->Context == NULL) { // // There was an error in dispatching the MRxDAVSrvCallWrapper method to // a worker thread. Complete the request and return STATUS_PENDING. // DavDbgTrace(DAV_TRACE_ERROR, ("%ld: MRxDAVCreateSrvCall/RxAllocatePoolWithTag.\n", PsGetCurrentThreadId())); SCCBC->Status = STATUS_INSUFFICIENT_RESOURCES; SrvCalldownStructure->CallBack(SCCBC); NtStatus = STATUS_PENDING; return NtStatus; } RtlZeroMemory(SrvCall->Context, sizeof(WEBDAV_SRV_CALL)); // // Check to see if the DAV server mentioned in the SrvCall exists. To do // this, we need to go to the usermode and call GetHostByName on the name // mentioned in the SrvCall strucutre. // RxContext = SrvCalldownStructure->RxContext; // // We need to pass the server name to the user mode to check whether such a // server actually exists. RxContext has 4 pointers that the mini-redirs // can use. Here we use MRxContext[1]. We store a reference to the SCCBC // strucutre which contains the name of the server. MRxContext[0] is used to // store a reference to the AsynEngineContext and this is done when the // context gets created in the function UMRxCreateAsyncEngineContext. The // pointer to SCCBC is also used while calling the callback function to // complete the creation of the SrvCall. // RxContext->MRxContext[1] = SCCBC; // // Dispatch the request to a system thread. // NtStatus = RxDispatchToWorkerThread((PRDBSS_DEVICE_OBJECT)MRxDAVDeviceObject, DelayedWorkQueue, MRxDAVSrvCallWrapper, RxContext); if (NtStatus == STATUS_SUCCESS) { // // Map the return value since the wrapper expects STATUS_PENDING. // NtStatus = STATUS_PENDING; } else { // // There was an error in dispatching the MRxDAVSrvCallWrapper method to // a worker thread. Complete the request and return STATUS_PENDING. // SCCBC->Status = NtStatus; SrvCalldownStructure->CallBack(SCCBC); NtStatus = STATUS_PENDING; } #else SCCBC->Status = STATUS_SUCCESS; SrvCalldownStructure->CallBack(SCCBC); NtStatus = STATUS_PENDING; #endif return(NtStatus); } VOID MRxDAVSrvCallWrapper( PVOID Context ) /*++ Routine Description: This routine is called by the worker thread. Its a routine that wraps the call to MRxDAVOuterWrapper. Arguments: RxContext - The RDBSS context. Return Value: RXSTATUS - The return status for the operation Notes: --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PRX_CONTEXT RxContext = (PRX_CONTEXT)Context; PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = NULL; PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = NULL; PMRX_SRV_CALL SrvCall = NULL; PWEBDAV_SRV_CALL DavSrvCall = NULL; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVSrvCallWrapper!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVSrvCallWrapper: RxContext: %08lx.\n", PsGetCurrentThreadId(), RxContext)); NtStatus = UMRxAsyncEngOuterWrapper(RxContext, SIZEOF_DAV_SPECIFIC_CONTEXT, MRxDAVFormatTheDAVContext, DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL, MRxDAVCreateSrvCallContinuation, "MRxDAVCreateSrvCall"); // // If we failed to queue the request to be sent to the usermode, then we // need to do some cleanup. If NtStatus is STATUS_CANCELLED then we would // have already done the cleanup in the MRxDAVHandleCreateSrvCallCancellation // funtcion. Hence we don't need to do it now. // if (NtStatus != STATUS_SUCCESS && NtStatus != STATUS_PENDING && NtStatus != STATUS_CANCELLED) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVSrvCallWrapper/UMRxAsyncEngOuterWrapper: " "NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus)); // // The SrvCall pointer is stored in the SCCBC structure which is // stored in the MRxContext[1] pointer of the RxContext structure. // This is done in the MRxDAVCreateSrvCall function. // ASSERT(RxContext->MRxContext[1] != NULL); SCCBC = (PMRX_SRVCALL_CALLBACK_CONTEXT)RxContext->MRxContext[1]; SrvCalldownStructure = SCCBC->SrvCalldownStructure; ASSERT(SrvCalldownStructure != NULL); SrvCall = SrvCalldownStructure->SrvCall; ASSERT(SrvCall != NULL); DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall); ASSERT(DavSrvCall != NULL); // // Free the memory that was allocatted for the SecurityClientContext in // the function MRxDAVFormatTheDAVContext. Before Freeing the memory, we // need to delete the SecurityClientContext. // if (DavSrvCall->SCAlreadyInitialized) { ASSERT(RxContext->MRxContext[2] != NULL); SeDeleteClientSecurity((PSECURITY_CLIENT_CONTEXT)RxContext->MRxContext[2]); RxFreePool(RxContext->MRxContext[2]); RxContext->MRxContext[2] = NULL; DavSrvCall->SCAlreadyInitialized = FALSE; } SCCBC->Status = NtStatus; SrvCalldownStructure->CallBack(SCCBC); } DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVSrvCallWrapper with NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return; } NTSTATUS MRxDAVCreateSrvCallContinuation( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE ) /*++ Routine Description: This routine checks to see if the server for which a SrvCall 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 MRxDAVCreateSrvCallContinuation!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVCreateSrvCallContinuation: " "AsyncEngineContext: %08lx, RxContext: %08lx\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); // // We are executing in the context of a worker thread. No point in holding // onto this thread. Set the Async flag irrespective of the nature of the // request. By nature we mean sync or async. Also since CreateSrvCall has // its own Callback, we do not need to call RxLowIoCompletion when the // AsyncEngineContext is getting finalized. // SetFlag(AsyncEngineContext->Flags, UMRX_ASYNCENG_CTX_FLAG_ASYNC_OPERATION); AsyncEngineContext->ShouldCallLowIoCompletion = FALSE; // // Try usermode. // NtStatus = UMRxSubmitAsyncEngUserModeRequest( UMRX_ASYNCENGINE_ARGUMENTS, MRxDAVFormatUserModeSrvCallCreateRequest, MRxDAVPrecompleteUserModeSrvCallCreateRequest ); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVCreateSrvCallContinuation with NtStatus =" " %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } NTSTATUS MRxDAVFormatUserModeSrvCallCreateRequest( 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 SrvCall 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 DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader; PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = NULL; PMRX_SRV_CALL SrvCall = NULL; PWCHAR ServerName = NULL; DWORD ServerNameLenInBytes = 0; PBYTE SecondaryBuff = NULL; PDAV_USERMODE_CREATE_SRVCALL_REQUEST SrvCallCreateReq = NULL; PSECURITY_CLIENT_CONTEXT SecurityClientContext = NULL; PSECURITY_SUBJECT_CONTEXT SecSubCtx = NULL; PNT_CREATE_PARAMETERS NtCP = &(RxContext->Create.NtCreateParameters); PACCESS_TOKEN AccessToken = NULL; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVFormatUserModeSrvCallCreateRequest!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVFormatUserModeSrvCallCreateRequest: " "AsyncEngineContext: %08lx, RxContext: %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); SrvCallCreateReq = &(DavWorkItem->CreateSrvCallRequest); // // Get the SecuritySubjectContext. // ASSERT(NtCP->SecurityContext->AccessState != NULL); SecSubCtx = &(NtCP->SecurityContext->AccessState->SubjectSecurityContext); // // Get the AccessToken. // AccessToken = SeQuerySubjectContextToken(SecSubCtx); // // Get the LogonID for this user/session. // if (!SeTokenIsRestricted(AccessToken)) { NtStatus = SeQueryAuthenticationIdToken(AccessToken, &(SrvCallCreateReq->LogonID)); if (NtStatus != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVFormatUserModeCreateSrvCallRequest/" "SeQueryAuthenticationIdToken. NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } } else { NtStatus = STATUS_ACCESS_DENIED; DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVFormatUserModeCreateSrvCallRequest/" "SeTokenIsRestricted. NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } // // Impersonate the client who initiated the request. If we fail to // impersonate, tough luck. The SecurityClientContext is stored in // RxContext->MRxContext[2]. This was done in MRxDAVFormatTheDAVContext. // ASSERT(RxContext->MRxContext[2] != NULL); SecurityClientContext = (PSECURITY_CLIENT_CONTEXT)RxContext->MRxContext[2]; if (SecurityClientContext != NULL) { NtStatus = UMRxImpersonateClient(SecurityClientContext, WorkItemHeader); if (!NT_SUCCESS(NtStatus)) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVFormatUserModeCreateSrvCallRequest/" "UMRxImpersonateClient. NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } } else { NtStatus = STATUS_INVALID_PARAMETER; DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVFormatUserModeCreateSrvCallRequest: " "SecurityClientContext is NULL.\n", PsGetCurrentThreadId())); goto EXIT_THE_FUNCTION; } DavWorkItem->WorkItemType = UserModeCreateSrvCall; SCCBC = (PMRX_SRVCALL_CALLBACK_CONTEXT)RxContext->MRxContext[1]; SrvCall = SCCBC->SrvCalldownStructure->SrvCall; // // Set the name of the server to be verified. We need to allocate memory // for the UserModeInfoBuff before filling in the ServerName in it. // ASSERT(SrvCall->pSrvCallName); ServerName = &(SrvCall->pSrvCallName->Buffer[1]); ServerNameLenInBytes = (1 + wcslen(ServerName)) * sizeof(WCHAR); SecondaryBuff = UMRxAllocateSecondaryBuffer(AsyncEngineContext, ServerNameLenInBytes); if (SecondaryBuff == NULL) { NtStatus = STATUS_INSUFFICIENT_RESOURCES; DavDbgTrace(DAV_TRACE_ERROR, ("ld: MRxDAVFormatUserModeSrvCallCreateRequest/" "UMRxAllocateSecondaryBuffer: ERROR: NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } SrvCallCreateReq->ServerName = (PWCHAR)SecondaryBuff; wcscpy(SrvCallCreateReq->ServerName, ServerName); DavDbgTrace(DAV_TRACE_DETAIL, ("ld: MRxDAVFormatUserModeSrvCallCreateRequest: ServerName = %ws\n", PsGetCurrentThreadId(), SrvCallCreateReq->ServerName)); if (RxContext->Create.UserName.Length) { RtlCopyMemory(DavWorkItem->UserName,RxContext->Create.UserName.Buffer,RxContext->Create.UserName.Length); } if (RxContext->Create.Password.Length) { RtlCopyMemory(DavWorkItem->Password,RxContext->Create.Password.Buffer,RxContext->Create.Password.Length); } EXIT_THE_FUNCTION: DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVFormatUserModeSrvCallCreateRequest with " "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } BOOL MRxDAVPrecompleteUserModeSrvCallCreateRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, BOOL OperationCancelled ) /*++ Routine Description: The precompletion routine for the create SrvCall 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: FALSE - UMRxAsyncEngineCalldownIrpCompletion is NOT called by the function UMRxCompleteUserModeRequest after we return. --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PDAV_USERMODE_WORKITEM WorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader; PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = NULL; PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = NULL; PMRX_SRV_CALL SrvCall = NULL; PDAV_USERMODE_CREATE_SRVCALL_REQUEST SrvCallCreateReq = NULL; PDAV_USERMODE_CREATE_SRVCALL_RESPONSE CreateSrvCallResponse = NULL; BOOL didFinalize = FALSE; PWEBDAV_SRV_CALL DavSrvCall = NULL; BOOL AsyncOperation = FALSE; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVPrecompleteUserModeSrvCallCreateRequest!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVPrecompleteUserModeSrvCallCreateRequest: " "AsyncEngineContext: %08lx, RxContext: %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); AsyncOperation = FlagOn(AsyncEngineContext->Flags, UMRX_ASYNCENG_CTX_FLAG_ASYNC_OPERATION); ASSERT(AsyncOperation == TRUE); // // We do the following only if the Operation has not been cancelled. If it // has been then this would have been done by the timer thread. // if (!OperationCancelled) { SCCBC = (PMRX_SRVCALL_CALLBACK_CONTEXT)RxContext->MRxContext[1]; ASSERT(SCCBC != NULL); SrvCalldownStructure = SCCBC->SrvCalldownStructure; ASSERT(SrvCalldownStructure != NULL); SrvCall = SrvCalldownStructure->SrvCall; ASSERT(SrvCall != NULL); // // We allocated memory for it, so it better not be NULL. // DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall); ASSERT(DavSrvCall != NULL); // // Free the memory that was allocatted for the SecurityClientContext in the // function MRxDAVFormatTheDAVContext. Before Freeing the memory, we need // to delete the SecurityClientContext. // ASSERT(DavSrvCall->SCAlreadyInitialized == TRUE); ASSERT(RxContext->MRxContext[2] != NULL); SeDeleteClientSecurity((PSECURITY_CLIENT_CONTEXT)RxContext->MRxContext[2]); RxFreePool(RxContext->MRxContext[2]); RxContext->MRxContext[2] = NULL; DavSrvCall->SCAlreadyInitialized = FALSE; } else { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: MRxDAVPrecompleteUserModeSrvCallCreateRequest: Operation Cancelled. " "AsyncEngineContext = %08lx, RxContext = %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); } SrvCallCreateReq = &(WorkItem->CreateSrvCallRequest); CreateSrvCallResponse = &(WorkItem->CreateSrvCallResponse); // // We need to free up the heap we allocated in the format routine. // if (SrvCallCreateReq->ServerName != NULL) { if (AsyncEngineContext->Status != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVPrecompleteUserModeSrvCallCreateRequest." " Server \"%ws\" is not a DAV server.\n", PsGetCurrentThreadId(), SrvCallCreateReq->ServerName)); } NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext, (PBYTE)SrvCallCreateReq->ServerName); if (NtStatus != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVPrecompleteUserModeSrvCallCreateRequest/" "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); } } if (!OperationCancelled) { // // Get this servers unique ID. // DavSrvCall->ServerID = CreateSrvCallResponse->ServerID; DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVPrecompleteUserModeSrvCallCreateRequest: " "ServerID = %ld assigned to this server entry.\n", PsGetCurrentThreadId(), DavSrvCall->ServerID)); // // Set the status in the callback structure. // SCCBC->Status = AsyncEngineContext->Status; } // // We call the first finalize here since we return STATUS_PENDING back to // the continuation routine in the create srvcall case. So the reference // that was made at the time of creation of the AsyncEngineContext is not // removed in the wrapper routine. The second finalize is because, we do not // call UMRxAsyncEngineCalldownIrpCompletion. // didFinalize = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) ); didFinalize = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) ); if (!OperationCancelled) { // // Call the callback function supplied by RDBSS. // SrvCalldownStructure->CallBack(SCCBC); } DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVPrecompleteUserModeSrvCallCreateRequest.\n", PsGetCurrentThreadId())); return FALSE; } NTSTATUS MRxDAVFinalizeSrvCall( PMRX_SRV_CALL pSrvCall, BOOLEAN Force ) /*++ Routine Description: This routine destroys a given server call instance. Arguments: pSrvCall - The server call instance to be disconnected. Force - TRUE if a disconnection is to be enforced immediately. Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PRX_CONTEXT RxContext = NULL; PRDBSS_DEVICE_OBJECT RxDeviceObject = pSrvCall->RxDeviceObject; PWEBDAV_SRV_CALL DavSrvCall; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVFinalizeSrvCall.\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVFinalizeSrvCall: SrvCall: %08lx, Force: %d.\n", PsGetCurrentThreadId(), pSrvCall, Force)); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVFinalizeSrvCall: SrvCallName: %wZ\n", PsGetCurrentThreadId(), pSrvCall->pSrvCallName)); // // We allocated memory for pSrvCall->Context, so it better not be NULL. // ASSERT(pSrvCall != NULL); // // If the MiniRedir didn't get a chance to allocate a SrvCall, then we // should return right away. // if (pSrvCall->Context == NULL) { DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: MRxDAVFinalizeSrvCall. pSrvCall->Context == NULL\n", PsGetCurrentThreadId())); return NtStatus; } ASSERT(pSrvCall->Context != NULL); // // If we did not create any server entry for this server in the user mode, // then we do not need to go to the user mode at all. This fact is // indicated by the ServerID field in the WEBDAV_SRV_CALL strucutre. If the // ID value is zero, that implies that the server entry was not created. // DavSrvCall = (PWEBDAV_SRV_CALL)pSrvCall->Context; if (DavSrvCall->ServerID == 0) { DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: No server entry was created in the user mode.\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: MRxDAVFinalizeSrvCall/RxCreateRxContext: " "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } // // We need to send the SrvCall to the format routine and use the // MRxContext[1] pointer of the RxContext structure to store it. // RxContext->MRxContext[1] = (PVOID)pSrvCall; NtStatus = UMRxAsyncEngOuterWrapper(RxContext, SIZEOF_DAV_SPECIFIC_CONTEXT, MRxDAVFormatTheDAVContext, DAV_MINIRDR_ENTRY_FROM_FINALIZESRVCALL, MRxDAVFinalizeSrvCallContinuation, "MRxDAVFinalizeSrvCall"); if (NtStatus != ERROR_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: MRxDAVFinalizeSrvCall/UMRxAsyncEngOuterWrapper: " "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); } EXIT_THE_FUNCTION: if (RxContext) { RxDereferenceAndDeleteRxContext(RxContext); } // // Free up the memory allocated for the context pointer. // RxFreePool(pSrvCall->Context); pSrvCall->Context = NULL; DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVFinalizeSrvCall with NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } NTSTATUS MRxDAVFinalizeSrvCallContinuation( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE ) /*++ Routine Description: This is the continuation routine which finalizes a SrvCall. 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 MRxDAVFinalizeSrvCallContinuation!!!!\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVFinalizeSrvCallContinuation: " "AsyncEngineContext: %08lx, RxContext: %08lx\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); // // Try usermode. // NtStatus = UMRxSubmitAsyncEngUserModeRequest( UMRX_ASYNCENGINE_ARGUMENTS, MRxDAVFormatUserModeSrvCallFinalizeRequest, MRxDAVPrecompleteUserModeSrvCallFinalizeRequest ); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVFinalizeSrvCallContinuation with NtStatus" " = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } NTSTATUS MRxDAVFormatUserModeSrvCallFinalizeRequest( 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 SrvCall 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; PDAV_USERMODE_FINALIZE_SRVCALL_REQUEST FinSrvCallReq = NULL; PWCHAR ServerName = NULL; ULONG ServerNameLengthInBytes = 0; PBYTE SecondaryBuff = NULL; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVFormatUserModeSrvCallFinalizeRequest.\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVFormatUserModeSrvCallFinalizeRequest: " "AsyncEngineContext: %08lx, RxContext: %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); // // SrvCall was set to MRxContext[0] in MRxDAVFinalizeSrvCall. We need it to // get the ServerID. // SrvCall = (PMRX_SRV_CALL)RxContext->MRxContext[1]; DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall); ASSERT(DavSrvCall != NULL); DavWorkItem->WorkItemType = UserModeFinalizeSrvCall; FinSrvCallReq = &(DavWorkItem->FinalizeSrvCallRequest); // // Set the ServerID. // FinSrvCallReq->ServerID = DavSrvCall->ServerID; // // 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: MRxDAVFormatUserModeSrvCallFinalizeRequest/" "UMRxAllocateSecondaryBuffer: ERROR: NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); goto EXIT_THE_FUNCTION; } FinSrvCallReq->ServerName = (PWCHAR)SecondaryBuff; wcscpy(FinSrvCallReq->ServerName, ServerName); EXIT_THE_FUNCTION: DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVFormatUserModeSrvCallFinalizeRequest " "with NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); return NtStatus; } BOOL MRxDAVPrecompleteUserModeSrvCallFinalizeRequest( UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE, PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader, ULONG WorkItemLength, BOOL OperationCancelled ) /*++ Routine Description: The precompletion routine for the finalize SrvCall 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_SRVCALL_REQUEST FinSrvCallReq; PAGED_CODE(); DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Entering MRxDAVPrecompleteUserModeSrvCallFinalizeRequest\n", PsGetCurrentThreadId())); DavDbgTrace(DAV_TRACE_CONTEXT, ("%ld: MRxDAVPrecompleteUserModeSrvCallFinalizeRequest: " "AsyncEngineContext: %08lx, RxContext: %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); FinSrvCallReq = &(WorkItem->FinalizeSrvCallRequest); if (OperationCancelled) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: MRxDAVPrecompleteUserModeSrvCallFinalizeRequest: Operation Cancelled. " "AsyncEngineContext = %08lx, RxContext = %08lx.\n", PsGetCurrentThreadId(), AsyncEngineContext, RxContext)); } // // We need to free up the heap we allocated in the format routine. // if (FinSrvCallReq->ServerName != NULL) { NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext, (PBYTE)FinSrvCallReq->ServerName); if (NtStatus != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVPrecompleteUserModeSrvCallFinalizeRequest/" "UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus)); } } if (AsyncEngineContext->Status != STATUS_SUCCESS) { DavDbgTrace(DAV_TRACE_ERROR, ("%ld: ERROR: MRxDAVPrecompleteUserModeSrvCallFinalizeRequest. " "Finalize SrvCall Failed!!!\n", PsGetCurrentThreadId())); } DavDbgTrace(DAV_TRACE_DETAIL, ("%ld: Leaving MRxDAVPrecompleteUserModeSrvCallFinalizeRequest\n", PsGetCurrentThreadId())); return TRUE; } NTSTATUS MRxDAVSrvCallWinnerNotify( IN PMRX_SRV_CALL pSrvCall, IN BOOLEAN ThisMinirdrIsTheWinner, IN OUT PVOID pSrvCallContext ) /*++ Routine Description: This routine finalizes the mini rdr context associated with an RDBSS Server call instance Arguments: pSrvCall - the Server Call ThisMinirdrIsTheWinner - TRUE if this mini rdr is the choosen one. pSrvCallContext - the server call context created by the mini redirector. Return Value: RXSTATUS - The return status for the operation Notes: The two phase construction protocol for Server calls is required because of parallel initiation of a number of mini redirectors. The RDBSS finalizes the particular mini redirector to be used in communicating with a given server based on quality of service criterion. --*/ { NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); return STATUS_SUCCESS; }