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
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
|
|
};
|
|
|
|
|