850 lines
28 KiB
C
850 lines
28 KiB
C
/*++
|
||
|
||
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
|
||
};
|
||
|
||
|