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.
 
 
 
 
 
 

850 lines
29 KiB

/*++
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 (pExtSessionSetupExchange->ResponseLength > pExtSessionSetupExchange->BufferLength) {
return STATUS_BUFFER_OVERFLOW;
}
if (BytesIndicated < pExtSessionSetupExchange->ResponseLength) {
// Set up the response for copying the data.
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
};