/*++ Copyright (c) 1989 Microsoft Corporation Module Name: exsessup.c Abstract: This module implements the routines for setting up a session using the the securitt negotiation mechanism ( post NT40 ). Author: Balan Sethu Raman [SethuR] 7-March-1995 Revision History: Notes: The extended session setup is used in the new security negotiation scheme which involves multiple round trips to the server before the user can be successfully authenticated and a session established. In the modified scheme the negotiate returns a BLOB which is passed to the client side security package to initiate the session setup procedure. The BLOB returned by the server contains an encoding of the security packages supported by the server. The client side security package when presented with this BLOB chooses a security package and encodes the client credentials in the form of a BLOB which is shipped to the server using the EXTENDED_SESSION_SETUP_ANDX SMB. The server has one of three responses to an EXTENDED_SESSION_SETUP_ANDX SMB presented by the client. 1) The server has enough information to establish the session. 2) The server cannot proceed with the session setup because of an error in the information presented by the client or otherwise. 3) The security package on the server needs an additional round trip before the session setup can be established. This is especially true of new security packages which support mutual authentication between the client and server. In the first two cases no further round trips are required. The action taken on the client side depends upon whether the server returned a BLOB. If the server returned a BLOB it must be presented to the client side security package to complete the session setup procedure. In the case of (3) the BLOB returned by the server must be presented to the client and the BLOB generated by the security package must be shipped back to the server. In the SMBCE_EXTENDED_SESSION_SETUP_EXCHANGE the following parameters support the protocol outlined above. A buffer with maximum server buffer size is allocated, locked and a MDL created as part of the exchange initialization. This buffer is used to hold the server response BLOB. Notice that this avoids redundant copying and handles all the known cases. --*/ #include "precomp.h" #pragma hdrstop #include "exsessup.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, SmbCeInitializeExtendedSessionSetupExchange) #pragma alloc_text(PAGE, SmbCeDiscardExtendedSessionSetupExchange) #pragma alloc_text(PAGE, SmbExtSecuritySessionSetupExchangeStart) #pragma alloc_text(PAGE, SmbExtSecuritySessionSetupExchangeSendCompletionHandler) #endif // this string is used to test whether the server really supports security signature. // if the server returns back the deferent string on SMB header security signature of the // extended session setup response from the client sends out on the request, the server // does support security signature. CHAR InitialSecuritySignature[] = {"BSRSPYL "}; extern BOOLEAN MRxSmbSecuritySignaturesEnabled; // // The Bug check file id for this module // #define BugCheckFileId (RDBSS_BUG_CHECK_SMB_NETROOT) // // The local debug trace level // #define Dbg (DEBUG_TRACE_DISPATCH) // // Forward declarations ... // NTSTATUS SmbCeInitializeExtendedSessionSetupExchange( PSMB_EXCHANGE* pExchangePtr, PMRX_V_NET_ROOT pVNetRoot) /*++ Routine Description: This routine initializes an instance of a session setup exchange. Arguments: pExchange - the exchange instance pVNetRoot - the MRX_V_NET_ROOT instance associated with the exchange. Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PSMB_EXTENDED_SESSION_SETUP_EXCHANGE pExtSessionSetupExchange; PAGED_CODE(); ASSERT((pExchangePtr == NULL) || ((*pExchangePtr)->Type == EXTENDED_SESSION_SETUP_EXCHANGE)); Status = SmbCeInitializeExchange( pExchangePtr, NULL, pVNetRoot, EXTENDED_SESSION_SETUP_EXCHANGE, &ExtendedSessionSetupExchangeDispatch); if (Status == STATUS_SUCCESS) { PSMBCEDB_SERVER_ENTRY pServerEntry; pServerEntry = SmbCeGetExchangeServerEntry(*pExchangePtr); pExtSessionSetupExchange = (PSMB_EXTENDED_SESSION_SETUP_EXCHANGE) (*pExchangePtr); pExtSessionSetupExchange->SmbCeFlags |= SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION; // Allocate the buffer to hold the server response. pExtSessionSetupExchange->BufferLength = pServerEntry->Server.MaximumBufferSize; pExtSessionSetupExchange->pActualBuffer = RxAllocatePoolWithTag( PagedPool, (pExtSessionSetupExchange->BufferLength + TRANSPORT_HEADER_SIZE), MRXSMB_KERBEROS_POOLTAG); pExtSessionSetupExchange->pServerResponseBlob = NULL; pExtSessionSetupExchange->ServerResponseBlobLength = 0; pExtSessionSetupExchange->Reparse = TRUE; if (pExtSessionSetupExchange->pActualBuffer != NULL) { (PCHAR) pExtSessionSetupExchange->pBuffer = (PCHAR) pExtSessionSetupExchange->pActualBuffer + TRANSPORT_HEADER_SIZE; RxAllocateHeaderMdl( pExtSessionSetupExchange->pBuffer, pExtSessionSetupExchange->BufferLength, pExtSessionSetupExchange->pBufferAsMdl ); if (pExtSessionSetupExchange->pBufferAsMdl != NULL) { RxProbeAndLockHeaderPages( pExtSessionSetupExchange->pBufferAsMdl, KernelMode, IoModifyAccess, Status); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } if (Status != STATUS_SUCCESS) { if (pExtSessionSetupExchange->pBufferAsMdl != NULL) { IoFreeMdl(pExtSessionSetupExchange->pBufferAsMdl); } if (pExtSessionSetupExchange->pActualBuffer != NULL) { RxFreePool(pExtSessionSetupExchange->pActualBuffer); } SmbCePrepareExchangeForReuse(*pExchangePtr); } } return Status; } VOID SmbCeDiscardExtendedSessionSetupExchange( PSMB_EXTENDED_SESSION_SETUP_EXCHANGE pExtSessionSetupExchange) /*++ Routine Description: This routine discards an instance of a session setup exchange. Arguments: pExchange - the exchange instance --*/ { PAGED_CODE(); if (pExtSessionSetupExchange->pBufferAsMdl != NULL) { RxUnlockHeaderPages(pExtSessionSetupExchange->pBufferAsMdl); IoFreeMdl(pExtSessionSetupExchange->pBufferAsMdl); } if (pExtSessionSetupExchange->pActualBuffer != NULL) { RxFreePool(pExtSessionSetupExchange->pActualBuffer); } if (pExtSessionSetupExchange->pServerResponseBlob != NULL) { RxFreePool(pExtSessionSetupExchange->pServerResponseBlob); } // Normally discrading the exchange results in the session state being // updated. In order to avoid race conditions between those exchanges // which are awaiting this construction and the updating of the session // state it is done locally. COnsequently the exchange state needs to be // updated so the the discard routine does not attempt it again. pExtSessionSetupExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_SESSION_CONSTRUCTOR; SmbCeDiscardExchange( (PSMB_EXCHANGE)pExtSessionSetupExchange); } NTSTATUS SmbExtSecuritySessionSetupExchangeStart( PSMB_EXCHANGE pExchange) /*++ Routine Description: This is the start routine for net root construction exchanges. This initiates the construction of the appropriate SMB's if required. Arguments: pExchange - the exchange instance Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; PSMB_EXTENDED_SESSION_SETUP_EXCHANGE pExtSessionSetupExchange; PSMB_HEADER pSmbHeader; PREQ_NT_EXTENDED_SESSION_SETUP_ANDX pSessionSetupRequest; PGENERIC_ANDX pGenericAndX; PSMBCEDB_SERVER_ENTRY pServerEntry; PSMBCEDB_SESSION_ENTRY pSessionEntry; ULONG SmbBufferUnconsumed; USHORT Flags2 = 0; PAGED_CODE(); pServerEntry = SmbCeGetExchangeServerEntry(pExchange); pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange); pExtSessionSetupExchange = (PSMB_EXTENDED_SESSION_SETUP_EXCHANGE)pExchange; if (!pExtSessionSetupExchange->FirstSessionSetup) { if (pSessionEntry->Header.State == SMBCEDB_ACTIVE) { return STATUS_SUCCESS; } else { return STATUS_USER_SESSION_DELETED; } } ASSERT((pExtSessionSetupExchange->Type == EXTENDED_SESSION_SETUP_EXCHANGE) && (pExtSessionSetupExchange->pBuffer != NULL) && (pExtSessionSetupExchange->pBufferAsMdl != NULL)); SmbCeLog(("ExtSecSessSetup - %lx %lx\n", pExtSessionSetupExchange->pServerResponseBlob, pSessionEntry)); SmbLog(LOG, SmbExtSecuritySessionSetupExchangeStart, LOGPTR(pExtSessionSetupExchange->pServerResponseBlob) LOGPTR(pSessionEntry)); pSmbHeader = (PSMB_HEADER)(pExtSessionSetupExchange->pBuffer); // Fill in the buffer header pSessionSetupRequest = (PREQ_NT_EXTENDED_SESSION_SETUP_ANDX)(pSmbHeader + 1); pGenericAndX = (PGENERIC_ANDX)pSessionSetupRequest; SmbBufferUnconsumed = pExtSessionSetupExchange->BufferLength - sizeof(SMB_HEADER); Flags2 |= (SMB_FLAGS2_UNICODE | SMB_FLAGS2_KNOWS_EAS | SMB_FLAGS2_KNOWS_LONG_NAMES | SMB_FLAGS2_NT_STATUS | SMB_FLAGS2_EXTENDED_SECURITY); *((PULONG)&pSmbHeader->Protocol) = SMB_HEADER_PROTOCOL; pSmbHeader->Flags = (SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS); pSmbHeader->Flags2 = Flags2; pSmbHeader->Pid = MRXSMB_PROCESS_ID; pSmbHeader->Uid = pSessionEntry->Session.UserId; pSmbHeader->Tid = 0; pSmbHeader->ErrorClass = 0; pSmbHeader->Reserved = 0; pSmbHeader->Command = SMB_COM_SESSION_SETUP_ANDX; SmbPutUshort(&pSmbHeader->Error,0); if (MRxSmbSecuritySignaturesEnabled) { pSmbHeader->Flags2 |= SMB_FLAGS2_SMB_SECURITY_SIGNATURE; } // Build the session setup and x. Status = SMBCE_SERVER_DIALECT_DISPATCH( &pServerEntry->Server, BuildSessionSetup, (pExchange, pGenericAndX, &SmbBufferUnconsumed)); if (Status == STATUS_SUCCESS) { // Update the buffer for the construction of the following SMB. SmbPutUshort( &pSessionSetupRequest->AndXOffset, (USHORT)(pExtSessionSetupExchange->BufferLength - SmbBufferUnconsumed)); pSessionSetupRequest->AndXCommand = SMB_COM_NO_ANDX_COMMAND; pSessionSetupRequest->AndXReserved = 0; if (pServerEntry->SecuritySignaturesEnabled && !pServerEntry->SecuritySignaturesActive) { RtlCopyMemory(pSmbHeader->SecuritySignature,InitialSecuritySignature,SMB_SECURITY_SIGNATURE_LENGTH); } } if (Status == STATUS_SUCCESS) { Status = SmbCeTranceive( pExchange, (RXCE_SEND_PARTIAL | RXCE_SEND_SYNCHRONOUS), pExtSessionSetupExchange->pBufferAsMdl, (pExtSessionSetupExchange->BufferLength - SmbBufferUnconsumed)); RxDbgTrace( 0, Dbg, ("Net Root SmbCeTranceive returned %lx\n",Status)); } return Status; } NTSTATUS ParseExtSecuritySessionSetupResponse( IN PSMB_EXTENDED_SESSION_SETUP_EXCHANGE pExtSessionSetupExchange, IN ULONG BytesIndicated, IN ULONG BytesAvailable, IN PSMB_HEADER pSmbHeader) /*++ Routine Description: This is the routine used to parse the extended session setup response from the server. Arguments: pExtSessionSetupExchange -- the exchange instance BytesIndicated -- the number of bytes indicated BytesAvailable -- the total number of bytes sent by the server pSmbHeader -- the SMB header ( beginning of the response) Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; ULONG ResponseLength; PRESP_NT_EXTENDED_SESSION_SETUP_ANDX pSessionSetupResponse; PSMBCEDB_SESSION_ENTRY pSessionEntry; if (BytesIndicated < sizeof(SMB_HEADER) + 1) { // Abort the exchange. No further processing can be done. return STATUS_INVALID_NETWORK_RESPONSE; } pSessionEntry = SmbCeGetExchangeSessionEntry(pExtSessionSetupExchange); pSessionSetupResponse = (PRESP_NT_EXTENDED_SESSION_SETUP_ANDX)(pSmbHeader + 1); if ((pSessionSetupResponse->WordCount != 4) && (pSessionSetupResponse->WordCount != 0)) { return STATUS_INVALID_NETWORK_RESPONSE; } // Parse the header and extract the status. The status has special significance // for further processing. If the server returns a BLOB and // STATUS_MORE_PROCESSING_REQUIRED additional round trips are required. pExtSessionSetupExchange->Status = GetSmbResponseNtStatus(pSmbHeader,(PSMB_EXCHANGE)pExtSessionSetupExchange); // Mask the errors returned by the security packagte on the server if (pExtSessionSetupExchange->Status == STATUS_INVALID_HANDLE) { pExtSessionSetupExchange->Status = STATUS_INVALID_NETWORK_RESPONSE; } //if no blob came back.....just get out if (pSessionSetupResponse->WordCount == 0) { pExtSessionSetupExchange->ServerResponseBlobLength = 0; return STATUS_SUCCESS; } // Squirrel away the UID on the first response. This UID needs to be used in // subsequent trips to complete the session establishment as it identifies // the session to the server. pSessionEntry->Session.UserId = pSmbHeader->Uid; if (FlagOn(SmbGetUshort(&pSessionSetupResponse->Action), SMB_SETUP_GUEST)) { pSessionEntry->Session.Flags |= SMBCE_SESSION_FLAGS_GUEST_SESSION; } RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseExtSecuritySessionSetupResponse BytesIndicated %ld\n",BytesIndicated)); RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseExtSecuritySessionSetupResponse BytesAvailable %ld\n",BytesAvailable)); // The bytes indicated should be atleast cover the SMB_HEADER and the // session setup response ( fixed portion ) ResponseLength = sizeof(SMB_HEADER) + FIELD_OFFSET( RESP_NT_EXTENDED_SESSION_SETUP_ANDX, Buffer); if (BytesIndicated > ResponseLength) { // Compute the extended session setup response length. pExtSessionSetupExchange->ResponseLength = ResponseLength + SmbGetUshort( &pSessionSetupResponse->ByteCount); RxDbgTrace(0,Dbg,("Kerberos session setup response length %ld\n",pExtSessionSetupExchange->ResponseLength)); if (BytesIndicated < pExtSessionSetupExchange->ResponseLength) { // Set up the response for copying the data. if (pExtSessionSetupExchange->ResponseLength > pExtSessionSetupExchange->BufferLength) { Status = STATUS_BUFFER_OVERFLOW; } else { Status = pExtSessionSetupExchange->Reparse ? STATUS_MORE_PROCESSING_REQUIRED : STATUS_INVALID_NETWORK_RESPONSE; } pExtSessionSetupExchange->Status = Status; } else { // set up the offsets in the response. pExtSessionSetupExchange->ServerResponseBlobOffset = sizeof(SMB_HEADER) + FIELD_OFFSET( RESP_NT_EXTENDED_SESSION_SETUP_ANDX, Buffer); pExtSessionSetupExchange->ServerResponseBlobLength = pSessionSetupResponse->SecurityBlobLength; // Copy the response onto the buffer associated with the exchange. RtlCopyMemory( pExtSessionSetupExchange->pBuffer, pSmbHeader, pExtSessionSetupExchange->ResponseLength); Status = STATUS_SUCCESS; } } else { // Abort the exchange. No further processing can be done. Status = STATUS_INVALID_NETWORK_RESPONSE; pExtSessionSetupExchange->Status = Status; } return Status; } NTSTATUS SmbExtSecuritySessionSetupExchangeReceive( IN struct _SMB_EXCHANGE *pExchange, // The exchange instance IN ULONG BytesIndicated, IN ULONG BytesAvailable, OUT ULONG *pBytesTaken, IN PSMB_HEADER pSmbHeader, OUT PMDL *pDataBufferPointer, OUT PULONG pDataSize, IN ULONG ReceiveFlags) /*++ Routine Description: This is the recieve indication handling routine for net root construction exchanges Arguments: pExchange - the exchange instance BytesIndicated - the number of bytes indicated Bytes Available - the number of bytes available pBytesTaken - the number of bytes consumed pSmbHeader - the byte buffer pDataBufferPointer - the buffer into which the remaining data is to be copied. pDataSize - the buffer size. Return Value: RXSTATUS - The return status for the operation Notes: This routine is called at DPC level. --*/ { NTSTATUS Status; PSMB_EXTENDED_SESSION_SETUP_EXCHANGE pExtSessionSetupExchange; PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange); ULONG SessionSetupResponseLength = 0; pExtSessionSetupExchange = (PSMB_EXTENDED_SESSION_SETUP_EXCHANGE)pExchange; if (pServerEntry->SecuritySignaturesEnabled && !pServerEntry->SecuritySignaturesActive && RtlCompareMemory(pSmbHeader->SecuritySignature, InitialSecuritySignature, SMB_SECURITY_SIGNATURE_LENGTH) != SMB_SECURITY_SIGNATURE_LENGTH) { pExtSessionSetupExchange->pResumptionContext->SecuritySignatureReturned = TRUE; } // Parse the response. Status = ParseExtSecuritySessionSetupResponse( pExtSessionSetupExchange, BytesIndicated, BytesAvailable, pSmbHeader); if (Status != STATUS_MORE_PROCESSING_REQUIRED) { *pBytesTaken = BytesAvailable; Status = STATUS_SUCCESS; } else { *pBytesTaken = 0; *pDataBufferPointer = pExtSessionSetupExchange->pBufferAsMdl; *pDataSize = pExtSessionSetupExchange->ResponseLength; } return Status; } NTSTATUS SmbExtSecuritySessionSetupExchangeSendCompletionHandler( IN PSMB_EXCHANGE pExchange, // The exchange instance IN PMDL pXmitBuffer, IN NTSTATUS SendCompletionStatus) /*++ Routine Description: This is the send call back indication handling routine for net root construction exchanges Arguments: pExchange - the exchange instance Return Value: RXSTATUS - The return status for the operation --*/ { return STATUS_SUCCESS; } NTSTATUS SmbExtSecuritySessionSetupExchangeCopyDataHandler( IN PSMB_EXCHANGE pExchange, // The exchange instance IN PMDL pCopyDataBuffer, IN ULONG DataSize) /*++ Routine Description: This is the copy data handling routine for net root construction exchanges Arguments: pExchange - the exchange instance Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; PSMB_EXTENDED_SESSION_SETUP_EXCHANGE pExtSessionSetupExchange; PSMB_HEADER pSmbHeader; pExtSessionSetupExchange = (PSMB_EXTENDED_SESSION_SETUP_EXCHANGE)pExchange; pSmbHeader = (PSMB_HEADER)(pExtSessionSetupExchange->pBuffer); Status = ParseExtSecuritySessionSetupResponse( pExtSessionSetupExchange, DataSize, DataSize, pSmbHeader); // At this time the parse routine cannot return STATUS_MORE_PROCESSING_REQUIRED // as the entire response has been consumed. if (Status == STATUS_MORE_PROCESSING_REQUIRED) { DbgPrint("Mapping Incomplete Server Response to Invalid Response\n"); SmbLogError(Status, LOG, SmbExtSecuritySessionSetupExchangeCopyDataHandler, LOGPTR(pExtSessionSetupExchange)); pExtSessionSetupExchange->Status = STATUS_INVALID_NETWORK_RESPONSE; } return STATUS_SUCCESS; } NTSTATUS SmbExtSecuritySessionSetupExchangeFinalize( PSMB_EXCHANGE pExchange, BOOLEAN *pPostFinalize) /*++ Routine Description: This routine finalkzes the construct net root exchange. It resumes the RDBSS by invoking the call back and discards the exchange Arguments: pExchange - the exchange instance CurrentIrql - the current interrupt request level pPostFinalize - a pointer to a BOOLEAN if the request should be posted Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; PSMB_EXTENDED_SESSION_SETUP_EXCHANGE pExtSessionSetupExchange; PSMBCE_RESUMPTION_CONTEXT pResumptionContext; pExtSessionSetupExchange = (PSMB_EXTENDED_SESSION_SETUP_EXCHANGE)pExchange; if (!pExtSessionSetupExchange->RequestPosted) { pExtSessionSetupExchange->RequestPosted = TRUE; *pPostFinalize = TRUE; return STATUS_SUCCESS; } else { // reset the flag since the exchange will be reused pExtSessionSetupExchange->RequestPosted = FALSE; *pPostFinalize = FALSE; } // Determine if further processing is required. If not finalize the // session entry. RxDbgTrace(0,Dbg, ("SmbExtSecuritySessionSetupExchangeFinalize: pESSExchange->Status = %lx\n",pExtSessionSetupExchange->Status)); // If the server returned STATUS_MORE_PROCESSING_REQUIRED and a BLOB was present // another trip to the server is required and we start all over again. if ((Status = pExtSessionSetupExchange->Status) != STATUS_MORE_PROCESSING_REQUIRED) { // The server returned an error other than STATUS_MORE_PROCESSING_REQUIRED // The session establishment can be completed based on whether the server // returned a BLOB. If a BLOB was returned it needs to be passed to the // local security package. This will enable the local security package to // either complete the session establishment successfully or to extract // extended error information from the BLOB. This can in turn be used to // propogate more meaningful errors to the client. if (Status == STATUS_SUCCESS && pExtSessionSetupExchange->ServerResponseBlobLength != 0) { PVOID pServerResponseBlob; // If we are not going back to the server an additional copy of the // server response BLOB is not required. pServerResponseBlob = ((PBYTE)pExtSessionSetupExchange->pBuffer + pExtSessionSetupExchange->ServerResponseBlobOffset); Status = ValidateServerExtendedSessionSetupResponse( pExtSessionSetupExchange, pServerResponseBlob, pExtSessionSetupExchange->ServerResponseBlobLength); } } else { // Make a copy of the server response blob so that the new session setup SMB // can be constructed if (pExtSessionSetupExchange->ServerResponseBlobLength != 0) { if (pExtSessionSetupExchange->pServerResponseBlob != NULL) { RxFreePool(pExtSessionSetupExchange->pServerResponseBlob); } pExtSessionSetupExchange->pServerResponseBlob = RxAllocatePoolWithTag( PagedPool, pExtSessionSetupExchange->ServerResponseBlobLength, MRXSMB_KERBEROS_POOLTAG); if (pExtSessionSetupExchange->pServerResponseBlob != NULL) { RtlCopyMemory( pExtSessionSetupExchange->pServerResponseBlob, ((PBYTE)pExtSessionSetupExchange->pBuffer + pExtSessionSetupExchange->ServerResponseBlobOffset), pExtSessionSetupExchange->ServerResponseBlobLength); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } } if (Status == STATUS_MORE_PROCESSING_REQUIRED) { PMRX_V_NET_ROOT pVNetRoot; USHORT SmbCeFlags; PRX_CONTEXT RxContext; pVNetRoot = pExtSessionSetupExchange->SmbCeContext.pVNetRoot; RxContext = pExtSessionSetupExchange->RxContext; // This is required so that the session state is not effected as the exchange // is prepared for reuse. This will enable us to avoid redundant initialization // as well as to carry over the state from one trip to another easily. ClearFlag( pExtSessionSetupExchange->SmbCeFlags, SMBCE_EXCHANGE_SESSION_CONSTRUCTOR); SmbCePrepareExchangeForReuse((PSMB_EXCHANGE)pExtSessionSetupExchange); // Note: By invoking SmbCeInitializeExchange as opposed to // SmbCeInitializeExtendedSessionSetupExchange only the connection engine // portion of the exchange is initialized. This will enable us to carry // over the state ( the server response BLOB ) from one trip to another // easily. Status = SmbCeInitializeExchange( (PSMB_EXCHANGE *)&pExtSessionSetupExchange, NULL, pVNetRoot, EXTENDED_SESSION_SETUP_EXCHANGE, &ExtendedSessionSetupExchangeDispatch); if (Status == STATUS_SUCCESS) { pExtSessionSetupExchange->SmbCeFlags |= SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION; pExtSessionSetupExchange->RxContext = RxContext; // Avoid duplicate counting during Exchange Initialization. SmbCeDecrementActiveExchangeCount(); // Set the session echange state to SMBCE_EXCHANGE_SESSION_INITIALIZED // so that the connection engine does not queue up the request the normal // way. This will force the connection engine to initiate immediately. pExtSessionSetupExchange->SmbCeState = SMBCE_EXCHANGE_SESSION_INITIALIZED; Status = SmbCeInitiateExchange((PSMB_EXCHANGE)pExtSessionSetupExchange); } } if (Status != STATUS_PENDING) { PSMBCEDB_SERVER_ENTRY pServerEntry; PSMBCEDB_SESSION_ENTRY pSessionEntry; SMBCEDB_OBJECT_STATE SessionState; RxDbgTrace(0,Dbg,("Kerberos Exchange Session Final Status(%lx)\n",Status)); pServerEntry = SmbCeGetExchangeServerEntry(pExtSessionSetupExchange); pSessionEntry = SmbCeGetExchangeSessionEntry(pExtSessionSetupExchange); pResumptionContext = pExtSessionSetupExchange->pResumptionContext; // Tear down the exchange instance ... SmbCeDiscardExtendedSessionSetupExchange(pExtSessionSetupExchange); if (pResumptionContext != NULL) { pResumptionContext->Status = Status; SmbCeResume(pResumptionContext); } } return STATUS_SUCCESS; } SMB_EXCHANGE_DISPATCH_VECTOR ExtendedSessionSetupExchangeDispatch = { SmbExtSecuritySessionSetupExchangeStart, SmbExtSecuritySessionSetupExchangeReceive, SmbExtSecuritySessionSetupExchangeCopyDataHandler, NULL, SmbExtSecuritySessionSetupExchangeFinalize, NULL };