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.
529 lines
17 KiB
529 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
kerbxchg.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the routines for setting up a kerberos session.
|
|
|
|
Author:
|
|
|
|
Balan Sethu Raman [SethuR] 7-March-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include <kerbxchg.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeStart)
|
|
#pragma alloc_text(PAGE, ParseKerberosSessionSetupResponse)
|
|
#pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeReceive)
|
|
#pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeSendCompletionHandler)
|
|
#pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeCopyDataHandler)
|
|
#pragma alloc_text(PAGE, SmbKerberosSessionSetupExchangeFinalize)
|
|
#endif
|
|
//
|
|
// 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 ...
|
|
//
|
|
|
|
#define KERBEROS_SESSION_SETUP_BUFFER_SIZE (4096)
|
|
|
|
NTSTATUS
|
|
SmbKerberosSessionSetupExchangeFinalize(
|
|
PSMB_EXCHANGE pExchange,
|
|
BOOLEAN *pPostFinalize);
|
|
|
|
|
|
NTSTATUS
|
|
SmbKerberosSessionSetupExchangeStart(
|
|
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_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange;
|
|
|
|
PAGED_CODE();
|
|
|
|
pKerberosExchange = (PSMB_KERBEROS_SESSION_SETUP_EXCHANGE)pExchange;
|
|
|
|
ASSERT(pKerberosExchange->Type == KERBEROS_SESSION_SETUP_EXCHANGE);
|
|
|
|
pKerberosExchange->BufferLength = KERBEROS_SESSION_SETUP_BUFFER_SIZE;
|
|
pKerberosExchange->pBuffer = RxAllocatePoolWithTag(
|
|
PagedPool,
|
|
pKerberosExchange->BufferLength,
|
|
MRXSMB_KERBEROS_POOLTAG);
|
|
pKerberosExchange->pServerResponseBlob = NULL;
|
|
pKerberosExchange->ServerResponseBlobLength = 0;
|
|
|
|
if (pKerberosExchange->pBuffer == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
PSMB_HEADER pSmbHeader = (PSMB_HEADER)(pKerberosExchange->pBuffer);
|
|
|
|
PREQ_NT_SESSION_SETUP_ANDX pSessionSetupRequest;
|
|
PGENERIC_ANDX pGenericAndX;
|
|
|
|
ULONG SmbBufferUnconsumed;
|
|
USHORT Flags2 = 0;
|
|
|
|
// Fill in the buffer header
|
|
pSessionSetupRequest = (PREQ_NT_SESSION_SETUP_ANDX)(pSmbHeader + 1);
|
|
pGenericAndX = (PGENERIC_ANDX)pSessionSetupRequest;
|
|
|
|
SmbBufferUnconsumed = pKerberosExchange->BufferLength - sizeof(SMB_HEADER);
|
|
|
|
ASSERT(pExchange->SmbCeContext.pServerEntry->Server.Dialect == CAIROX_DIALECT);
|
|
|
|
Flags2 |= (SMB_FLAGS2_UNICODE |
|
|
SMB_FLAGS2_KNOWS_EAS |
|
|
SMB_FLAGS2_KNOWS_LONG_NAMES |
|
|
SMB_FLAGS2_NT_STATUS);
|
|
|
|
*((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 = 0;
|
|
pSmbHeader->Tid = 0;
|
|
pSmbHeader->ErrorClass = 0;
|
|
pSmbHeader->Reserved = 0;
|
|
pSmbHeader->Command = SMB_COM_SESSION_SETUP_ANDX;
|
|
SmbPutUshort(&pSmbHeader->Error,0);
|
|
|
|
// Build the session setup and x.
|
|
Status = SMBCE_SERVER_DIALECT_DISPATCH(
|
|
&pExchange->SmbCeContext.pServerEntry->Server,
|
|
BuildSessionSetup,
|
|
(pExchange,
|
|
pGenericAndX,
|
|
&SmbBufferUnconsumed));
|
|
|
|
if (Status == RX_MAP_STATUS(SUCCESS)) {
|
|
// Update the buffer for the construction of the following SMB.
|
|
SmbPutUshort(&pSessionSetupRequest->AndXOffset,
|
|
(USHORT)(pKerberosExchange->BufferLength - SmbBufferUnconsumed));
|
|
pSessionSetupRequest->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
|
|
pSessionSetupRequest->AndXReserved = 0;
|
|
} else {
|
|
if (Status == RX_MAP_STATUS(NO_LOGON_SERVERS)) {
|
|
// If no kerberos logon servers are available downgrade to a downlevel
|
|
// connection and retry.
|
|
pKerberosExchange->SmbCeContext.pServerEntry->Server.Dialect = NTLANMAN_DIALECT;
|
|
}
|
|
|
|
SmbCeReferenceSessionEntry(pKerberosExchange->SmbCeContext.pSessionEntry);
|
|
SmbCeUpdateSessionEntryState(
|
|
pExchange->SmbCeContext.pSessionEntry,
|
|
SMBCEDB_INVALID);
|
|
SmbCeCompleteSessionEntryInitialization(pExchange->SmbCeContext.pSessionEntry);
|
|
pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_SESSION_CONSTRUCTOR;
|
|
}
|
|
|
|
if (Status == RX_MAP_STATUS(SUCCESS)) {
|
|
pKerberosExchange->pBufferAsMdl = RxAllocateMdl(
|
|
pKerberosExchange->pBuffer,
|
|
KERBEROS_SESSION_SETUP_BUFFER_SIZE);
|
|
if (pKerberosExchange->pBufferAsMdl != NULL) {
|
|
RxProbeAndLockPages(
|
|
pKerberosExchange->pBufferAsMdl,
|
|
KernelMode,
|
|
IoModifyAccess,
|
|
Status);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = SmbCeTranceive(
|
|
pExchange,
|
|
(RXCE_SEND_PARTIAL | RXCE_SEND_SYNCHRONOUS),
|
|
pKerberosExchange->pBufferAsMdl,
|
|
(pKerberosExchange->BufferLength -
|
|
SmbBufferUnconsumed));
|
|
|
|
RxDbgTrace( 0, Dbg, ("Net Root SmbCeTranceive returned %lx\n",Status));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ParseKerberosSessionSetupResponse(
|
|
IN PSMB_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange,
|
|
IN ULONG BytesIndicated,
|
|
IN ULONG BytesAvailable,
|
|
IN PSMB_HEADER pSmbHeader)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ResponseLength;
|
|
|
|
PAGED_CODE();
|
|
|
|
// The SMB exchange completed without an error.
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated %ld\n",BytesIndicated));
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated %ld\n",BytesIndicated));
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader 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_SESSION_SETUP_ANDX,Buffer);
|
|
if (BytesIndicated > ResponseLength) {
|
|
PRESP_SESSION_SETUP_ANDX pSessionSetupResponse;
|
|
|
|
pSessionSetupResponse = (PRESP_SESSION_SETUP_ANDX)(pSmbHeader + 1);
|
|
|
|
pKerberosExchange->ResponseLength = ResponseLength +
|
|
SmbGetUshort(&pSessionSetupResponse->ByteCount);
|
|
|
|
pKerberosExchange->SmbCeContext.pSessionEntry->Session.UserId = pSmbHeader->Uid;
|
|
|
|
RxDbgTrace(0,Dbg,("Kerberos session setup response length %ld\n",pKerberosExchange->ResponseLength));
|
|
|
|
if (BytesIndicated < pKerberosExchange->ResponseLength) {
|
|
// Set up the response for copying the data.
|
|
if (pKerberosExchange->ResponseLength > pKerberosExchange->BufferLength) {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
} else {
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
} else {
|
|
// The regular session setup response consists of three strings corresponding
|
|
// to the server's operating system type, lanman type and the domain name.
|
|
// Skip past the three strings to locate the kerberos blob that has been
|
|
// returned which needs to be autheticated locally.
|
|
|
|
// ***** NOTE ******
|
|
// Currently the server changes made by Arnold do not support the three
|
|
// strings that were previously returned by the Server, viz., the operating
|
|
// system name, the LANMAN version and the domain name. If the server is
|
|
// changed in this regard the corresponding change neeeds to be made here.
|
|
|
|
// set up the offsets in the response.
|
|
pKerberosExchange->ServerResponseBlobOffset = sizeof(SMB_HEADER) +
|
|
FIELD_OFFSET(RESP_SESSION_SETUP_ANDX,Buffer);
|
|
pKerberosExchange->ServerResponseBlobLength = pSessionSetupResponse->ByteCount;
|
|
|
|
// Copy the response onto the buffer associated with the exchange.
|
|
RtlCopyMemory(pKerberosExchange->pBuffer,
|
|
pSmbHeader,
|
|
pKerberosExchange->ResponseLength);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
// Abort the exchange. No further processing can be done.
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbKerberosSessionSetupExchangeReceive(
|
|
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)
|
|
/*++
|
|
|
|
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_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange;
|
|
|
|
ULONG SessionSetupResponseLength = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
pKerberosExchange = (PSMB_KERBEROS_SESSION_SETUP_EXCHANGE)pExchange;
|
|
|
|
// Parse the response. Finalize the exchange instance if all the data is available
|
|
Status = ParseKerberosSessionSetupResponse(
|
|
pKerberosExchange,
|
|
BytesIndicated,
|
|
BytesAvailable,
|
|
pSmbHeader);
|
|
|
|
if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
|
|
*pBytesTaken = BytesAvailable;
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
*pBytesTaken = 0;
|
|
*pDataBufferPointer = pKerberosExchange->pBufferAsMdl;
|
|
*pDataSize = pKerberosExchange->ResponseLength;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbKerberosSessionSetupExchangeSendCompletionHandler(
|
|
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
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbKerberosSessionSetupExchangeCopyDataHandler(
|
|
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
|
|
|
|
--*/
|
|
{
|
|
PSMB_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange;
|
|
PSMB_HEADER pSmbHeader;
|
|
|
|
PAGED_CODE();
|
|
|
|
pKerberosExchange = (PSMB_KERBEROS_SESSION_SETUP_EXCHANGE)pExchange;
|
|
pSmbHeader = (PSMB_HEADER)pCopyDataBuffer;
|
|
|
|
pKerberosExchange->Status = ParseKerberosSessionSetupResponse(
|
|
pKerberosExchange,
|
|
DataSize,
|
|
DataSize,
|
|
pSmbHeader);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbKerberosSessionSetupExchangeFinalize(
|
|
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_KERBEROS_SESSION_SETUP_EXCHANGE pKerberosExchange;
|
|
PSMBCE_RESUMPTION_CONTEXT pResumptionContext;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
if (RxShouldPostCompletion()) {
|
|
*pPostFinalize = TRUE;
|
|
return RX_MAP_STATUS(SUCCESS);
|
|
} else {
|
|
*pPostFinalize = FALSE;
|
|
}
|
|
|
|
pKerberosExchange = (PSMB_KERBEROS_SESSION_SETUP_EXCHANGE)pExchange;
|
|
|
|
// A copying operation on the server response BLOB is avoided by temporarily
|
|
// setting up the exchange pointer to the original buffer in which the response
|
|
// was received and initiating a allocation only if required.
|
|
pKerberosExchange->pServerResponseBlob =
|
|
((PBYTE)pKerberosExchange->pBuffer +
|
|
pKerberosExchange->ServerResponseBlobOffset);
|
|
|
|
// Determine if further processing is required. If not finalize the
|
|
// session entry.
|
|
RxDbgTrace(0,Dbg,
|
|
("SmbKerberosSessionSetupExchangeFinalize: pKerberosExchange->Status = %lx\n",pKerberosExchange->Status));
|
|
|
|
if (pKerberosExchange->Status == RX_MAP_STATUS(SUCCESS)) {
|
|
Status = KerberosValidateServerResponse(pKerberosExchange);
|
|
}
|
|
|
|
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
|
pKerberosExchange->pServerResponseBlob = RxAllocatePoolWithTag(
|
|
PagedPool,
|
|
pKerberosExchange->ServerResponseBlobLength,
|
|
MRXSMB_KERBEROS_POOLTAG);
|
|
|
|
if (pKerberosExchange->pServerResponseBlob != NULL) {
|
|
RtlCopyMemory(
|
|
pKerberosExchange->pServerResponseBlob,
|
|
((PBYTE)pKerberosExchange->pBuffer +
|
|
pKerberosExchange->ServerResponseBlobOffset),
|
|
pKerberosExchange->ServerResponseBlobLength);
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
} else {
|
|
pKerberosExchange->pServerResponseBlob = NULL;
|
|
}
|
|
|
|
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
|
Status = SmbCeInitiateExchange((PSMB_EXCHANGE)pKerberosExchange);
|
|
} else {
|
|
// Reset the constructor flags in the exchange.
|
|
pKerberosExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_SESSION_CONSTRUCTOR;
|
|
|
|
if (pKerberosExchange->pServerResponseBlob != NULL) {
|
|
RxFreePool(pKerberosExchange->pServerResponseBlob);
|
|
}
|
|
|
|
RxDbgTrace(0,Dbg,("Kerberos Exchange Session Final Status(%lx)\n",Status));
|
|
|
|
// Finalize the session based upon the status
|
|
if (Status == STATUS_SUCCESS) {
|
|
SmbCeUpdateSessionEntryState(
|
|
pKerberosExchange->SmbCeContext.pSessionEntry,
|
|
SMBCEDB_ACTIVE);
|
|
} else {
|
|
if (Status == RX_MAP_STATUS(NO_LOGON_SERVERS)) {
|
|
// If no kerberos logon servers are available downgrade to a downlevel
|
|
// connection and retry.
|
|
pKerberosExchange->SmbCeContext.pServerEntry->Server.Dialect = NTLANMAN_DIALECT;
|
|
}
|
|
|
|
SmbCeUpdateSessionEntryState(
|
|
pKerberosExchange->SmbCeContext.pSessionEntry,
|
|
SMBCEDB_INVALID);
|
|
}
|
|
|
|
// Complete the session construction.
|
|
|
|
SmbCeReferenceSessionEntry(pKerberosExchange->SmbCeContext.pSessionEntry);
|
|
SmbCeCompleteSessionEntryInitialization(pKerberosExchange->SmbCeContext.pSessionEntry);
|
|
pKerberosExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_SESSION_CONSTRUCTOR;
|
|
|
|
pResumptionContext = pKerberosExchange->pResumptionContext;
|
|
|
|
// Tear down the exchange instance ...
|
|
SmbCeDiscardExchange(pKerberosExchange);
|
|
|
|
if (pResumptionContext != NULL) {
|
|
pResumptionContext->Status = Status;
|
|
SmbCeResume(pResumptionContext);
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
SMB_EXCHANGE_DISPATCH_VECTOR
|
|
KerberosSessionSetupExchangeDispatch =
|
|
{
|
|
SmbKerberosSessionSetupExchangeStart,
|
|
SmbKerberosSessionSetupExchangeReceive,
|
|
SmbKerberosSessionSetupExchangeCopyDataHandler,
|
|
NULL,
|
|
SmbKerberosSessionSetupExchangeFinalize
|
|
};
|
|
|
|
|