mirror of https://github.com/tongzx/nt5src
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.
1956 lines
67 KiB
1956 lines
67 KiB
/*++ BUILD Version: 0009 // Increment this if a change has global effects
|
|
Copyright (c) 1987-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sessetup.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the Session setup related routines
|
|
|
|
Author:
|
|
|
|
Balan Sethu Raman (SethuR) 06-Mar-95 Created
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
#include "exsessup.h"
|
|
#include "ntlsapi.h"
|
|
#include "mrxsec.h"
|
|
#include "rdrssp\kfuncs.h"
|
|
#include "rdrssp\secret.h"
|
|
|
|
#include <wincred.h>
|
|
#include <secpkg.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, BuildSessionSetupSmb)
|
|
#pragma alloc_text(PAGE, BuildNtLanmanResponsePrologue)
|
|
#pragma alloc_text(PAGE, BuildNtLanmanResponseEpilogue)
|
|
#pragma alloc_text(PAGE, BuildExtendedSessionSetupResponsePrologue)
|
|
#pragma alloc_text(PAGE, BuildExtendedSessionSetupResponseEpilogue)
|
|
#endif
|
|
|
|
extern BOOLEAN MRxSmbSecuritySignaturesEnabled;
|
|
|
|
UNICODE_STRING CifsServiceName = { 8, 10, L"cifs" };
|
|
|
|
NTSTATUS
|
|
BuildSessionSetupSmb(
|
|
PSMB_EXCHANGE pExchange,
|
|
PGENERIC_ANDX pAndXSmb,
|
|
PULONG pAndXSmbBufferSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds the session setup SMB for a NT server
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
pAndXSmb - the session setup to be filled in
|
|
|
|
pAndXSmbBufferSize - the SMB buffer size on input modified to remaining size on
|
|
output.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
Eventhough the general structure of the code tries to isolate dialect specific issues
|
|
as much as possible this routine takes the opposite approach. This is because of the
|
|
preamble and prologue to security interaction which far outweigh the dialect specific
|
|
work required to be done. Therefore in the interests of a smaller footprint this approach
|
|
has been adopted.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PSMBCEDB_SESSION_ENTRY pSessionEntry;
|
|
PSMBCE_SERVER pServer;
|
|
PSMBCE_SESSION pSession;
|
|
|
|
PREQ_SESSION_SETUP_ANDX pSessionSetup;
|
|
PREQ_NT_SESSION_SETUP_ANDX pNtSessionSetup;
|
|
PREQ_NT_EXTENDED_SESSION_SETUP_ANDX pExtendedNtSessionSetup;
|
|
|
|
ULONG OriginalBufferSize = *pAndXSmbBufferSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
|
|
pServer = SmbCeGetExchangeServer(pExchange);
|
|
pSession = SmbCeGetExchangeSession(pExchange);
|
|
|
|
// There are three different variants of session setup and X that can be shipped to the
|
|
// server. All three of them share some common fields. The setting of these common fields
|
|
// is done in all the three cases by accessing the passed in buffer as an instance of
|
|
// REQ_SESSION_SETUP_ANDX. The fields specific to the remaining two are conditionalized upon
|
|
// accessing the same buffer as an instance of REQ_NT_SESSION_SETUP_ANDX and
|
|
// REQ_EXTENDED_NT_SESSION_SETUP_ANDX respectively. This implies that great care must be
|
|
// taken in shuffling the fields in these three structs.
|
|
|
|
pSessionSetup = (PREQ_SESSION_SETUP_ANDX)pAndXSmb;
|
|
pNtSessionSetup = (PREQ_NT_SESSION_SETUP_ANDX)pSessionSetup;
|
|
pExtendedNtSessionSetup = (PREQ_NT_EXTENDED_SESSION_SETUP_ANDX)pSessionSetup;
|
|
|
|
pSessionSetup->AndXCommand = 0xff; // No ANDX
|
|
pSessionSetup->AndXReserved = 0x00; // Reserved (MBZ)
|
|
|
|
SmbPutUshort(&pSessionSetup->AndXOffset, 0x0000); // No AndX as of yet.
|
|
|
|
// Since we can allocate pool dynamically, we set our buffer size
|
|
// to match that of the server.
|
|
SmbPutUshort(&pSessionSetup->MaxBufferSize, (USHORT)pServer->MaximumBufferSize);
|
|
SmbPutUshort(&pSessionSetup->MaxMpxCount, pServer->MaximumRequests);
|
|
|
|
SmbPutUshort(&pSessionSetup->VcNumber, (USHORT)pSessionEntry->SessionVCNumber);
|
|
|
|
SmbPutUlong(&pSessionSetup->SessionKey, pServer->SessionKey);
|
|
SmbPutUlong(&pSessionSetup->Reserved, 0);
|
|
|
|
if (pServer->Dialect == NTLANMAN_DIALECT) {
|
|
// Set up the NT server session setup specific parameters.
|
|
if (FlagOn(pServer->DialectFlags,DF_EXTENDED_SECURITY) &&
|
|
!FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) {
|
|
SmbPutUshort(&pExtendedNtSessionSetup->WordCount,12);
|
|
|
|
// Set the capabilities
|
|
SmbPutUlong(
|
|
&pExtendedNtSessionSetup->Capabilities,
|
|
(CAP_NT_STATUS |
|
|
CAP_UNICODE |
|
|
CAP_LEVEL_II_OPLOCKS |
|
|
CAP_NT_SMBS |
|
|
CAP_DYNAMIC_REAUTH |
|
|
CAP_EXTENDED_SECURITY));
|
|
} else {
|
|
SmbPutUshort(&pNtSessionSetup->WordCount,13);
|
|
|
|
// Set the capabilities
|
|
SmbPutUlong(
|
|
&pNtSessionSetup->Capabilities,
|
|
(CAP_NT_STATUS |
|
|
CAP_UNICODE |
|
|
CAP_LEVEL_II_OPLOCKS |
|
|
CAP_NT_SMBS ));
|
|
}
|
|
} else {
|
|
SmbPutUshort(&pSessionSetup->WordCount,10);
|
|
}
|
|
|
|
// Build the security information in the session setup SMB.
|
|
Status = BuildSessionSetupSecurityInformation(
|
|
pExchange,
|
|
(PBYTE)pSessionSetup,
|
|
pAndXSmbBufferSize);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
// Copy the operating system name and the LANMAN version info
|
|
// position the buffer for copying the operating system name and the lanman type.
|
|
PBYTE pBuffer = (PBYTE)pSessionSetup +
|
|
OriginalBufferSize -
|
|
*pAndXSmbBufferSize;
|
|
|
|
if (FlagOn(pServer->DialectFlags,DF_UNICODE)){
|
|
|
|
//
|
|
// Make sure the UNICODE string is suitably aligned
|
|
//
|
|
if( ((ULONG_PTR)pBuffer) & 01 ) {
|
|
pBuffer++;
|
|
(*pAndXSmbBufferSize)--;
|
|
}
|
|
|
|
Status = SmbPutUnicodeString(
|
|
&pBuffer,
|
|
&SmbCeContext.OperatingSystem,
|
|
pAndXSmbBufferSize);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
Status = SmbPutUnicodeString(
|
|
&pBuffer,
|
|
&SmbCeContext.LanmanType,
|
|
pAndXSmbBufferSize);
|
|
}
|
|
} else {
|
|
Status = SmbPutUnicodeStringAsOemString(
|
|
&pBuffer,
|
|
&SmbCeContext.OperatingSystem,
|
|
pAndXSmbBufferSize);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = SmbPutUnicodeStringAsOemString(
|
|
&pBuffer,
|
|
&SmbCeContext.LanmanType,
|
|
pAndXSmbBufferSize);
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if (pServer->Dialect == NTLANMAN_DIALECT) {
|
|
if (FlagOn(pServer->DialectFlags,DF_EXTENDED_SECURITY) &&
|
|
!FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) {
|
|
SmbPutUshort(
|
|
&pExtendedNtSessionSetup->ByteCount,
|
|
(USHORT)(OriginalBufferSize -
|
|
FIELD_OFFSET(REQ_NT_EXTENDED_SESSION_SETUP_ANDX,Buffer) -
|
|
*pAndXSmbBufferSize));
|
|
} else {
|
|
SmbPutUshort(
|
|
&pNtSessionSetup->ByteCount,
|
|
(USHORT)(OriginalBufferSize -
|
|
FIELD_OFFSET(REQ_NT_SESSION_SETUP_ANDX,Buffer) -
|
|
*pAndXSmbBufferSize));
|
|
}
|
|
} else {
|
|
SmbPutUshort(
|
|
&pSessionSetup->ByteCount,
|
|
(USHORT)(OriginalBufferSize -
|
|
FIELD_OFFSET(REQ_SESSION_SETUP_ANDX,Buffer) -
|
|
*pAndXSmbBufferSize));
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
BuildNtLanmanResponsePrologue(
|
|
PSMB_EXCHANGE pExchange,
|
|
PUNICODE_STRING pUserName,
|
|
PUNICODE_STRING pDomainName,
|
|
PSTRING pCaseSensitiveResponse,
|
|
PSTRING pCaseInsensitiveResponse,
|
|
PSECURITY_RESPONSE_CONTEXT pResponseContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds the security related information for the session setup SMB to
|
|
without extended security negotiation
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
This routine needs to be executed in the system process in order to protect virtual memory
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
NTSTATUS FinalStatus;
|
|
|
|
UNICODE_STRING ServerName;
|
|
UNICODE_STRING TargetServerName;
|
|
|
|
PVOID pTargetInformation;
|
|
ULONG TargetInformationSize;
|
|
ULONG ExtraSize = 0;
|
|
PVOID ExtraServerTargetInfo = NULL;
|
|
|
|
SecBufferDesc InputToken;
|
|
SecBuffer InputBuffer[2];
|
|
SecBufferDesc *pOutputBufferDescriptor = NULL;
|
|
SecBuffer *pOutputBuffer = NULL;
|
|
ULONG_PTR OutputBufferDescriptorSize;
|
|
|
|
ULONG LsaFlags = ISC_REQ_ALLOCATE_MEMORY;
|
|
TimeStamp Expiry;
|
|
PCHALLENGE_MESSAGE InToken = NULL;
|
|
ULONG InTokenSize;
|
|
PNTLM_CHALLENGE_MESSAGE NtlmInToken = NULL;
|
|
ULONG NtlmInTokenSize = 0;
|
|
PAUTHENTICATE_MESSAGE OutToken = NULL;
|
|
PNTLM_INITIALIZE_RESPONSE NtlmOutToken = NULL;
|
|
PUCHAR p = NULL;
|
|
ULONG_PTR AllocateSize;
|
|
|
|
PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
|
|
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
|
|
|
PAGED_CODE();
|
|
|
|
try {
|
|
pResponseContext->KerberosSetup.pOutputContextBuffer = NULL;
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
//
|
|
// If this is a remote boot session and we do not have the proper
|
|
// credentials to log in to the machine account, then use the NULL
|
|
// session.
|
|
//
|
|
|
|
if (FlagOn(pSession->Flags, SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) &&
|
|
!MRxSmbRemoteBootDoMachineLogon) {
|
|
|
|
//
|
|
// Remote boot session with no credentials. Set up a NULL session.
|
|
//
|
|
|
|
pCaseSensitiveResponse->Length = 0;
|
|
pCaseSensitiveResponse->MaximumLength = 0;
|
|
pCaseSensitiveResponse->Buffer = NULL;
|
|
pCaseInsensitiveResponse->Length = 0;
|
|
pCaseInsensitiveResponse->MaximumLength = 0;
|
|
pCaseInsensitiveResponse->Buffer = NULL;
|
|
pDomainName->Length = 0;
|
|
pDomainName->MaximumLength = 0;
|
|
pDomainName->Buffer = NULL;
|
|
pUserName->Length = 0;
|
|
pUserName->MaximumLength = 0;
|
|
pUserName->Buffer = NULL;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else
|
|
#endif // defined(REMOTE_BOOT)
|
|
{
|
|
SmbCeGetServerName(
|
|
pExchange->SmbCeContext.pVNetRoot->pNetRoot->pSrvCall,
|
|
&ServerName);
|
|
|
|
if (pServerEntry->DomainName.Length && pServerEntry->DomainName.Buffer) {
|
|
TargetServerName = ServerName;
|
|
ExtraSize = ServerName.Length;
|
|
ExtraServerTargetInfo = ServerName.Buffer;
|
|
ServerName = pServerEntry->DomainName;
|
|
}
|
|
|
|
TargetInformationSize = ServerName.Length;
|
|
pTargetInformation = ServerName.Buffer;
|
|
|
|
InTokenSize = sizeof(CHALLENGE_MESSAGE) + TargetInformationSize + ExtraSize;
|
|
|
|
NtlmInTokenSize = sizeof(NTLM_CHALLENGE_MESSAGE);
|
|
|
|
if (pSession->pPassword != NULL) {
|
|
NtlmInTokenSize += pSession->pPassword->Length;
|
|
LsaFlags |= ISC_REQ_USE_SUPPLIED_CREDS;
|
|
}
|
|
|
|
if (pSession->pUserName != NULL) {
|
|
NtlmInTokenSize += pSession->pUserName->Length;
|
|
LsaFlags |= ISC_REQ_USE_SUPPLIED_CREDS;
|
|
}
|
|
|
|
if (pSession->pUserDomainName != NULL) {
|
|
NtlmInTokenSize += pSession->pUserDomainName->Length;
|
|
LsaFlags |= ISC_REQ_USE_SUPPLIED_CREDS;
|
|
}
|
|
|
|
// For Alignment purposes, we want InTokenSize rounded up to
|
|
// the nearest word size.
|
|
|
|
AllocateSize = ((InTokenSize + 3) & ~3) + NtlmInTokenSize;
|
|
|
|
InToken = ExAllocatePool(
|
|
PagedPool,
|
|
AllocateSize );
|
|
|
|
if ( InToken == NULL )
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
try_return( Status );
|
|
|
|
}
|
|
|
|
// Allocate the output buffer
|
|
OutputBufferDescriptorSize = sizeof(SecBufferDesc) + 2 * sizeof(SecBuffer);
|
|
|
|
pOutputBufferDescriptor = ExAllocatePool(
|
|
PagedPool,
|
|
OutputBufferDescriptorSize );
|
|
|
|
if ( pOutputBufferDescriptor == NULL )
|
|
{
|
|
Status = STATUS_NO_MEMORY ;
|
|
try_return( Status );
|
|
|
|
}
|
|
|
|
pOutputBuffer = (SecBuffer *)(pOutputBufferDescriptor + 1);
|
|
pResponseContext->KerberosSetup.pOutputContextBuffer = pOutputBufferDescriptor;
|
|
|
|
RxDbgTrace(0,Dbg,("Allocate pool %p\n", InToken));
|
|
|
|
// partition off the NTLM in token part of the
|
|
// buffer
|
|
if (LsaFlags & ISC_REQ_USE_SUPPLIED_CREDS)
|
|
{
|
|
NtlmInToken = (PNTLM_CHALLENGE_MESSAGE) ((PUCHAR) InToken + InTokenSize);
|
|
NtlmInToken = (PNTLM_CHALLENGE_MESSAGE) (((ULONG_PTR) NtlmInToken + 3) & ~3);
|
|
RtlZeroMemory(NtlmInToken,NtlmInTokenSize);
|
|
p = (PUCHAR) NtlmInToken + sizeof(NTLM_CHALLENGE_MESSAGE);
|
|
}
|
|
|
|
if(!SecIsValidHandle(&pSession->CredentialHandle)) {
|
|
UNICODE_STRING LMName;
|
|
TimeStamp LifeTime;
|
|
|
|
LMName.Buffer = (PWSTR) InToken;
|
|
LMName.Length = NTLMSP_NAME_SIZE;
|
|
LMName.MaximumLength = LMName.Length;
|
|
RtlCopyMemory(
|
|
LMName.Buffer,
|
|
NTLMSP_NAME,
|
|
NTLMSP_NAME_SIZE);
|
|
|
|
|
|
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) ||
|
|
MRxSmbUseKernelModeSecurity) {
|
|
ULONG fCredentialUse = SECPKG_CRED_OUTBOUND;
|
|
|
|
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) {
|
|
fCredentialUse |= SECPKG_CRED_OWF_PASSWORD;
|
|
}
|
|
|
|
Status = AcquireCredentialsHandleK(
|
|
NULL,
|
|
&LMName,
|
|
fCredentialUse,
|
|
&pSession->LogonId,
|
|
NULL,
|
|
NULL,
|
|
(PVOID)1,
|
|
&pSession->CredentialHandle,
|
|
&LifeTime);
|
|
} else {
|
|
Status = AcquireCredentialsHandleW(
|
|
NULL,
|
|
&LMName,
|
|
SECPKG_CRED_OUTBOUND,
|
|
&pSession->LogonId,
|
|
NULL,
|
|
NULL,
|
|
(PVOID)1,
|
|
&pSession->CredentialHandle,
|
|
&LifeTime);
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
SecInvalidateHandle( &pSession->CredentialHandle );
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildNtLanmanResponsePrologue_1,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
|
|
// We need to free the output buffer (and description) because if they are valid,
|
|
// BuildNtLanmanResponseEpilogue will try and parse them, and they have not been
|
|
// initialized yet...
|
|
ExFreePool( pOutputBufferDescriptor );
|
|
pResponseContext->KerberosSetup.pOutputContextBuffer = NULL;
|
|
|
|
try_return(Status);
|
|
}
|
|
}
|
|
|
|
// Copy in the pass,user,domain if they were specified
|
|
if(pSession->pPassword != NULL) {
|
|
NtlmInToken->Password.Length = pSession->pPassword->Length;
|
|
NtlmInToken->Password.MaximumLength = pSession->pPassword->Length;
|
|
RtlCopyMemory(
|
|
p,
|
|
pSession->pPassword->Buffer,
|
|
pSession->pPassword->Length);
|
|
NtlmInToken->Password.Buffer = (ULONG) (p - (PUCHAR)NtlmInToken);
|
|
p += pSession->pPassword->Length;
|
|
}
|
|
|
|
if(pSession->pUserName != NULL) {
|
|
NtlmInToken->UserName.Length = pSession->pUserName->Length;
|
|
NtlmInToken->UserName.MaximumLength = pSession->pUserName->Length;
|
|
RtlCopyMemory(
|
|
p,
|
|
pSession->pUserName->Buffer,
|
|
pSession->pUserName->Length);
|
|
NtlmInToken->UserName.Buffer = (ULONG) (p - (PUCHAR)NtlmInToken);
|
|
p += pSession->pUserName->Length;
|
|
}
|
|
|
|
if (pSession->pUserDomainName != NULL) {
|
|
NtlmInToken->DomainName.Length = pSession->pUserDomainName->Length;
|
|
NtlmInToken->DomainName.MaximumLength = pSession->pUserDomainName->Length;
|
|
RtlCopyMemory(
|
|
p,
|
|
pSession->pUserDomainName->Buffer,
|
|
pSession->pUserDomainName->Length);
|
|
NtlmInToken->DomainName.Buffer = (ULONG) (p - (PUCHAR)NtlmInToken);
|
|
p += pSession->pUserDomainName->Length;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
InToken->Signature,
|
|
NTLMSSP_SIGNATURE,
|
|
sizeof(NTLMSSP_SIGNATURE));
|
|
InToken->MessageType = NtLmChallenge;
|
|
|
|
InToken->NegotiateFlags = NTLMSSP_NEGOTIATE_UNICODE |
|
|
NTLMSSP_NEGOTIATE_OEM |
|
|
NTLMSSP_REQUEST_INIT_RESPONSE;
|
|
|
|
if (pServerEntry->Server.SecurityMode == SECURITY_MODE_SHARE_LEVEL) {
|
|
InToken->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXPORTED_CONTEXT;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
InToken->Challenge,
|
|
pServer->EncryptionKey,
|
|
MSV1_0_CHALLENGE_LENGTH);
|
|
|
|
InToken->TargetName.Length =
|
|
InToken->TargetName.MaximumLength = (USHORT)TargetInformationSize;
|
|
InToken->TargetName.Buffer = sizeof(CHALLENGE_MESSAGE);
|
|
|
|
RtlCopyMemory(
|
|
(PCHAR)InToken + sizeof(CHALLENGE_MESSAGE),
|
|
pTargetInformation,
|
|
TargetInformationSize);
|
|
|
|
TargetServerName.Buffer = (PWCHAR) ((PCHAR)InToken +
|
|
sizeof(CHALLENGE_MESSAGE) +
|
|
TargetInformationSize);
|
|
|
|
if (ExtraSize) {
|
|
RtlCopyMemory(
|
|
TargetServerName.Buffer,
|
|
ExtraServerTargetInfo,
|
|
ExtraSize);
|
|
|
|
InToken->NegotiateFlags |= NTLMSSP_TARGET_TYPE_DOMAIN;
|
|
} else {
|
|
InToken->NegotiateFlags |= NTLMSSP_TARGET_TYPE_SERVER;
|
|
}
|
|
|
|
InputToken.pBuffers = InputBuffer;
|
|
InputToken.cBuffers = 1;
|
|
InputToken.ulVersion = 0;
|
|
InputBuffer[0].pvBuffer = InToken;
|
|
InputBuffer[0].cbBuffer = InTokenSize;
|
|
InputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
|
|
|
if (LsaFlags & ISC_REQ_USE_SUPPLIED_CREDS)
|
|
{
|
|
InputToken.cBuffers = 2;
|
|
InputBuffer[1].pvBuffer = NtlmInToken;
|
|
InputBuffer[1].cbBuffer = NtlmInTokenSize;
|
|
InputBuffer[1].BufferType = SECBUFFER_TOKEN;
|
|
}
|
|
|
|
pOutputBufferDescriptor->pBuffers = pOutputBuffer;
|
|
pOutputBufferDescriptor->cBuffers = 2;
|
|
pOutputBufferDescriptor->ulVersion = 0;
|
|
pOutputBuffer[0].pvBuffer = NULL;
|
|
pOutputBuffer[0].cbBuffer = 0;
|
|
pOutputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
|
pOutputBuffer[1].pvBuffer = NULL;
|
|
pOutputBuffer[1].cbBuffer = 0;
|
|
pOutputBuffer[1].BufferType = SECBUFFER_TOKEN;
|
|
|
|
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) ||
|
|
MRxSmbUseKernelModeSecurity) {
|
|
Status = InitializeSecurityContextK(
|
|
&pSession->CredentialHandle,
|
|
(PCtxtHandle)NULL,
|
|
ExtraSize ? &TargetServerName : NULL,
|
|
LsaFlags,
|
|
0,
|
|
SECURITY_NATIVE_DREP,
|
|
&InputToken,
|
|
0,
|
|
&pSession->SecurityContextHandle,
|
|
pOutputBufferDescriptor,
|
|
&FinalStatus,
|
|
&Expiry);
|
|
} else {
|
|
Status = InitializeSecurityContextW(
|
|
&pSession->CredentialHandle,
|
|
(PCtxtHandle)NULL,
|
|
ExtraSize ? &TargetServerName : NULL,
|
|
LsaFlags,
|
|
0,
|
|
SECURITY_NATIVE_DREP,
|
|
&InputToken,
|
|
0,
|
|
&pSession->SecurityContextHandle,
|
|
pOutputBufferDescriptor,
|
|
&FinalStatus,
|
|
&Expiry);
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) ||
|
|
MRxSmbUseKernelModeSecurity) {
|
|
Status = MapSecurityErrorK(Status);
|
|
} else {
|
|
Status = MapSecurityError(Status);
|
|
}
|
|
SmbCeLog(("IniSecCtxStat %p %lx\n",SmbCeGetExchangeSessionEntry(pExchange),Status));
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildNtLanmanResponsePrologue_2,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
|
|
try_return(Status);
|
|
}
|
|
|
|
OutToken = (PAUTHENTICATE_MESSAGE) pOutputBuffer[0].pvBuffer;
|
|
|
|
ASSERT(OutToken != NULL);
|
|
RxDbgTrace(0,Dbg,("InitSecCtxt OutToken is %p\n", OutToken));
|
|
|
|
if (OutToken == NULL) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildNtLanmanResponsePrologue_3,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
try_return(Status);
|
|
}
|
|
|
|
// The security response the pointers are encoded in terms off the offset
|
|
// from the beginning of the buffer. Make the appropriate adjustments.
|
|
|
|
if (ARGUMENT_PRESENT(pCaseSensitiveResponse)) {
|
|
pCaseSensitiveResponse->Length = OutToken->NtChallengeResponse.Length;
|
|
pCaseSensitiveResponse->MaximumLength = OutToken->NtChallengeResponse.MaximumLength;
|
|
pCaseSensitiveResponse->Buffer = (PBYTE)OutToken + (ULONG_PTR)OutToken->NtChallengeResponse.Buffer;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(pCaseInsensitiveResponse)) {
|
|
pCaseInsensitiveResponse->Length = OutToken->LmChallengeResponse.Length;
|
|
pCaseInsensitiveResponse->MaximumLength = OutToken->LmChallengeResponse.MaximumLength;
|
|
pCaseInsensitiveResponse->Buffer = (PBYTE)OutToken + (ULONG_PTR)OutToken->LmChallengeResponse.Buffer;
|
|
}
|
|
|
|
if (pSession->pUserDomainName != NULL) {
|
|
*pDomainName = *(pSession->pUserDomainName);
|
|
} else {
|
|
pDomainName->Length = OutToken->DomainName.Length;
|
|
pDomainName->MaximumLength = pDomainName->Length;
|
|
pDomainName->Buffer = (PWCHAR)((PBYTE)OutToken + (ULONG_PTR)OutToken->DomainName.Buffer);
|
|
}
|
|
|
|
if (pSession->pUserName != NULL) {
|
|
*pUserName = *(pSession->pUserName);
|
|
} else {
|
|
pUserName->Length = OutToken->UserName.Length;
|
|
pUserName->MaximumLength = OutToken->UserName.MaximumLength;
|
|
pUserName->Buffer = (PWCHAR)((PBYTE)OutToken + (ULONG_PTR)OutToken->UserName.Buffer);
|
|
}
|
|
|
|
NtlmOutToken = pOutputBuffer[1].pvBuffer;
|
|
if (NtlmOutToken != NULL) {
|
|
RtlCopyMemory(
|
|
pSession->UserSessionKey,
|
|
NtlmOutToken->UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
|
|
RtlCopyMemory(
|
|
pSession->LanmanSessionKey,
|
|
NtlmOutToken->LanmanSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH);
|
|
}
|
|
}
|
|
|
|
try_exit:NOTHING;
|
|
} finally {
|
|
if (InToken != NULL) {
|
|
|
|
ExFreePool( InToken );
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
BuildNtLanmanResponseEpilogue(pExchange, pResponseContext);
|
|
} else {
|
|
// This routine can be call from tree connect request, the SecurityContextHandle
|
|
// will be overwritten if not deleted, which causes pool leak on LSA.
|
|
DeleteSecurityContextForSession(pSession);
|
|
}
|
|
}
|
|
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildNtLanmanResponsePrologue,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
BuildNtLanmanResponseEpilogue(
|
|
PSMB_EXCHANGE pExchange,
|
|
PSECURITY_RESPONSE_CONTEXT pResponseContext)
|
|
/*++
|
|
This routine needs to be executed in the system process in order to protect virtual memory
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
|
|
|
|
PAGED_CODE();
|
|
|
|
if (pResponseContext->KerberosSetup.pOutputContextBuffer != NULL) {
|
|
ULONG i = 0;
|
|
SecBufferDesc *pBufferDescriptor = (SecBufferDesc *)pResponseContext->KerberosSetup.pOutputContextBuffer;
|
|
SecBuffer *pBuffer = pBufferDescriptor->pBuffers;
|
|
ULONG_PTR BufferDescriptorSize = sizeof(SecBufferDesc) + 2 * sizeof(SecBuffer);
|
|
|
|
for (i = 0; i < pBufferDescriptor->cBuffers; i++) {
|
|
if (pBuffer[i].pvBuffer != NULL) {
|
|
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) ||
|
|
MRxSmbUseKernelModeSecurity) {
|
|
FreeContextBufferK(pBuffer[i].pvBuffer);
|
|
} else {
|
|
FreeContextBuffer(pBuffer[i].pvBuffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
ExFreePool( pBufferDescriptor );
|
|
|
|
pResponseContext->KerberosSetup.pOutputContextBuffer = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BuildExtendedSessionSetupResponsePrologue(
|
|
PSMB_EXCHANGE pExchange,
|
|
PVOID pSecurityBlobPtr,
|
|
PUSHORT pSecurityBlobSize,
|
|
PSECURITY_RESPONSE_CONTEXT pResponseContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds the security related information for the session setup SMB to
|
|
a NT server with extended security
|
|
|
|
Arguments:
|
|
|
|
pExchange - the SMB_EXCHANGE that's going on for this call. If this is a
|
|
subsequent call, this exchange will have the server's security
|
|
blob.
|
|
|
|
pSecurityBlobPtr - On entry, pointer to where in the SMB to stick the security
|
|
blob destined for the server.
|
|
|
|
pSecurityBlobSize - On entry, the max size allowed for a security blob. On
|
|
exit, the actual size of the blob.
|
|
|
|
pResponseContext -
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
Eventhough the genral structure of the code tries to isolate dialect specific issues
|
|
as much as possible this routine takes the opposite approach. This is because of the
|
|
preamble and prologue to security interaction which far outweigh the dialect specific
|
|
work required to be done. Therefore in the interests of a smaller footprint this approach
|
|
has been adopted.
|
|
|
|
This routine needs to be executed in the system process in order to protect virtual memory
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SECURITY_STATUS SecStatus;
|
|
|
|
ULONG Catts;
|
|
TimeStamp Expiry;
|
|
|
|
ULONG LsaFlags = (ISC_REQ_MUTUAL_AUTH |
|
|
ISC_REQ_DELEGATE |
|
|
ISC_REQ_FRAGMENT_TO_FIT );
|
|
ULONG_PTR RemoteBlobOffset;
|
|
ULONG_PTR OutputBufferSize;
|
|
|
|
UNICODE_STRING PrincipalName = { 0 };
|
|
PUNICODE_STRING pServerPrincipalName;
|
|
|
|
PVOID pServerSecurityBlob;
|
|
ULONG ServerSecurityBlobSize;
|
|
|
|
PUCHAR pTempBlob = NULL;
|
|
|
|
PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
|
|
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
|
|
|
UNICODE_STRING ServerName;
|
|
BOOLEAN bTempServerName = FALSE;
|
|
PUNICODE_STRING pServerDomainName;
|
|
UNICODE_STRING TargetInfoMarshalled;
|
|
|
|
PSMBCE_EXTENDED_SESSION pExtendedSession;
|
|
PSMB_EXTENDED_SESSION_SETUP_EXCHANGE pExtendedSessionSetupExchange;
|
|
|
|
SecBufferDesc InputToken;
|
|
SecBuffer InputBuffer;
|
|
SecBufferDesc OutputToken;
|
|
SecBuffer OutputBuffer;
|
|
|
|
PCtxtHandle pInputContextHandle = NULL;
|
|
ULONG SpnSize = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT((pExchange->Type == EXTENDED_SESSION_SETUP_EXCHANGE) &&
|
|
(pSession->Type == EXTENDED_NT_SESSION));
|
|
|
|
SmbCeAcquireResource();
|
|
|
|
if (pServerEntry->DnsName.Buffer != NULL) {
|
|
ServerName.Length = pServerEntry->DnsName.Length;
|
|
ServerName.MaximumLength = pServerEntry->DnsName.MaximumLength;
|
|
|
|
ServerName.Buffer = RxAllocatePoolWithTag(PagedPool,ServerName.MaximumLength,MRXSMB_SERVER_POOLTAG);
|
|
|
|
if (ServerName.Buffer) {
|
|
RtlCopyMemory(ServerName.Buffer,
|
|
pServerEntry->DnsName.Buffer,
|
|
pServerEntry->DnsName.Length);
|
|
|
|
bTempServerName = TRUE;
|
|
} else {
|
|
SmbCeReleaseResource();
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
|
|
//DbgPrint("DNS name is used for session setup %wZ\n", &ServerName);
|
|
} else {
|
|
SmbCeGetServerName(
|
|
pExchange->SmbCeContext.pVNetRoot->pNetRoot->pSrvCall,
|
|
&ServerName);
|
|
}
|
|
|
|
SmbCeReleaseResource();
|
|
|
|
ASSERT(ServerName.MaximumLength > (ServerName.Length + sizeof(WCHAR)));
|
|
|
|
if ((pExchange->RxContext != NULL) &&
|
|
(pExchange->RxContext->MajorFunction == IRP_MJ_CREATE) &&
|
|
((pExchange->RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT)) ||
|
|
(pExchange->RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT)))) {
|
|
ASSERT(pExchange->RxContext->Create.NtCreateParameters.DfsNameContext != NULL);
|
|
|
|
if (pSession->TargetInfoMarshalled == NULL) {
|
|
PDFS_NAME_CONTEXT DfsNameContext = (PDFS_NAME_CONTEXT)pExchange->RxContext->Create.NtCreateParameters.DfsNameContext;
|
|
|
|
if (DfsNameContext->pDfsTargetInfo) {
|
|
PCREDENTIAL_TARGET_INFORMATIONW InTargetInfo = DfsNameContext->pDfsTargetInfo;
|
|
#if 0
|
|
DbgPrint("DFS TargetInfo is used %x\n",InTargetInfo);
|
|
DbgPrint("TargeInfo TargetName %ws\n",InTargetInfo->TargetName);
|
|
DbgPrint("TargeInfo NetbiosServerName %ws\n",InTargetInfo->NetbiosServerName);
|
|
DbgPrint("TargeInfo DnsServerName %ws\n",InTargetInfo->DnsServerName);
|
|
DbgPrint("TargeInfo NetbiosDomainName %ws\n",InTargetInfo->NetbiosDomainName);
|
|
DbgPrint("TargeInfo DnsDomainName %ws\n",InTargetInfo->DnsDomainName);
|
|
DbgPrint("TargeInfo DnsTreeName %ws\n",InTargetInfo->DnsTreeName);
|
|
DbgPrint("TargeInfo CredTypes %ws\n",InTargetInfo->CredTypes);
|
|
DbgPrint("TargeInfo TargetNameFlags %x\n",InTargetInfo->Flags);
|
|
DbgPrint("TargeInfo CredTypeCount %x\n",InTargetInfo->CredTypeCount);
|
|
#endif
|
|
Status = CredMarshalTargetInfo(
|
|
InTargetInfo,
|
|
&pSession->TargetInfoMarshalled,
|
|
&pSession->TargetInfoLength);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
goto FINALLY;
|
|
}
|
|
} else if (DfsNameContext->pLMRTargetInfo){
|
|
PLMR_QUERY_TARGET_INFO LmrTargetInfo = DfsNameContext->pLMRTargetInfo;
|
|
|
|
#if 0
|
|
DbgPrint("LMR TargetInfo is used %x\n",LmrTargetInfo);
|
|
#endif
|
|
|
|
pSession->TargetInfoMarshalled = RxAllocatePoolWithTag(PagedPool,
|
|
LmrTargetInfo->BufferLength,
|
|
MRXSMB_SESSION_POOLTAG);
|
|
|
|
if (pSession->TargetInfoMarshalled == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
|
|
pSession->TargetInfoLength = LmrTargetInfo->BufferLength;
|
|
RtlCopyMemory(pSession->TargetInfoMarshalled,
|
|
LmrTargetInfo->TargetInfoMarshalled,
|
|
LmrTargetInfo->BufferLength);
|
|
}
|
|
}
|
|
}
|
|
|
|
TargetInfoMarshalled.Buffer = pSession->TargetInfoMarshalled;
|
|
TargetInfoMarshalled.Length =
|
|
TargetInfoMarshalled.MaximumLength = (USHORT)pSession->TargetInfoLength;
|
|
|
|
Status = SecMakeSPNEx(
|
|
&CifsServiceName,
|
|
&ServerName,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
(pSession->TargetInfoMarshalled? &TargetInfoMarshalled : NULL),
|
|
&PrincipalName,
|
|
&SpnSize,
|
|
TRUE );
|
|
|
|
|
|
pExtendedSessionSetupExchange = (PSMB_EXTENDED_SESSION_SETUP_EXCHANGE)pExchange;
|
|
pExtendedSession = (PSMBCE_EXTENDED_SESSION)pSession;
|
|
|
|
pResponseContext->KerberosSetup.pOutputContextBuffer = NULL;
|
|
|
|
pServerPrincipalName = pExchange->SmbCeContext.pVNetRoot->pNetRoot->pSrvCall->pPrincipalName;
|
|
|
|
RxDbgTrace(0,Dbg,("KerberosResponsePrologue: Prinicpal name length %ld\n",PrincipalName.Length));
|
|
|
|
|
|
if ( ( pExtendedSessionSetupExchange->pServerResponseBlob == NULL) &&
|
|
( !SecIsValidHandle( &pExtendedSession->SecurityContextHandle ) ) ) {
|
|
// This is the first time. Pass in the BLOB obtained during NEGOTIATE to
|
|
// the client side security package.
|
|
|
|
ServerSecurityBlobSize = pServer->NtServer.SecurityBlobLength;
|
|
pServerSecurityBlob = pServer->NtServer.pSecurityBlob;
|
|
} else {
|
|
ServerSecurityBlobSize = pExtendedSessionSetupExchange->ServerResponseBlobLength;
|
|
pServerSecurityBlob = pExtendedSessionSetupExchange->pServerResponseBlob;
|
|
}
|
|
|
|
try {
|
|
|
|
if( !SecIsValidHandle( &pExtendedSession->CredentialHandle )) {
|
|
// Obtain a credential handle
|
|
UNICODE_STRING KerberosName;
|
|
TimeStamp LifeTime;
|
|
|
|
ULONG_PTR CredentialBufferLength;
|
|
PSEC_WINNT_AUTH_IDENTITY_EX pCredentialBuffer;
|
|
|
|
PBYTE pStringBuffer;
|
|
|
|
// The supplied credentials need to be packaged for the kerberos package
|
|
// These need to be supplied in a special format as speced out by the
|
|
// security packages.
|
|
|
|
CredentialBufferLength = 0;
|
|
pCredentialBuffer = NULL;
|
|
|
|
if(pSession->pUserName != NULL) {
|
|
CredentialBufferLength += pSession->pUserName->Length + sizeof(WCHAR);
|
|
}
|
|
|
|
if (pSession->pUserDomainName != NULL) {
|
|
CredentialBufferLength += pSession->pUserDomainName->Length + sizeof(WCHAR);
|
|
}
|
|
|
|
if(pSession->pPassword != NULL) {
|
|
CredentialBufferLength += pSession->pPassword->Length + sizeof(WCHAR);
|
|
}
|
|
|
|
if (CredentialBufferLength != 0) {
|
|
CredentialBufferLength += sizeof(SEC_WINNT_AUTH_IDENTITY_EX);
|
|
|
|
pCredentialBuffer = ExAllocatePool( PagedPool, CredentialBufferLength );
|
|
|
|
if ( pCredentialBuffer == NULL )
|
|
{
|
|
Status = STATUS_NO_MEMORY ;
|
|
try_return( Status );
|
|
|
|
}
|
|
|
|
//
|
|
// Zero all the fixed length fields
|
|
//
|
|
|
|
RtlZeroMemory( pCredentialBuffer, sizeof( SEC_WINNT_AUTH_IDENTITY_EX ) );
|
|
|
|
pCredentialBuffer->Version = SEC_WINNT_AUTH_IDENTITY_VERSION ;
|
|
pCredentialBuffer->Length = sizeof( SEC_WINNT_AUTH_IDENTITY_EX );
|
|
pCredentialBuffer->Flags = (SEC_WINNT_AUTH_IDENTITY_UNICODE |
|
|
SEC_WINNT_AUTH_IDENTITY_MARSHALLED);
|
|
|
|
pStringBuffer = (PBYTE) (pCredentialBuffer + 1);
|
|
|
|
if (pSession->pUserName != NULL) {
|
|
pCredentialBuffer->UserLength = pSession->pUserName->Length / sizeof(WCHAR);
|
|
pCredentialBuffer->User = (PWCHAR)pStringBuffer;
|
|
|
|
RtlCopyMemory(
|
|
pCredentialBuffer->User,
|
|
pSession->pUserName->Buffer,
|
|
pSession->pUserName->Length);
|
|
|
|
pStringBuffer += pSession->pUserName->Length;
|
|
|
|
SmbPutUshort(pStringBuffer,L'\0');
|
|
pStringBuffer += sizeof(WCHAR);
|
|
}
|
|
|
|
if (pSession->pUserDomainName != NULL) {
|
|
pCredentialBuffer->DomainLength = pSession->pUserDomainName->Length / sizeof(WCHAR);
|
|
pCredentialBuffer->Domain = (PWCHAR)pStringBuffer;
|
|
|
|
RtlCopyMemory(
|
|
pCredentialBuffer->Domain,
|
|
pSession->pUserDomainName->Buffer,
|
|
pSession->pUserDomainName->Length);
|
|
|
|
pStringBuffer += pSession->pUserDomainName->Length;
|
|
|
|
SmbPutUshort(pStringBuffer,L'\0');
|
|
pStringBuffer += sizeof(WCHAR);
|
|
}
|
|
|
|
if (pSession->pPassword != NULL) {
|
|
pCredentialBuffer->PasswordLength = pSession->pPassword->Length / sizeof(WCHAR);
|
|
pCredentialBuffer->Password = (PWCHAR)pStringBuffer;
|
|
|
|
RtlCopyMemory(
|
|
pCredentialBuffer->Password,
|
|
pSession->pPassword->Buffer,
|
|
pSession->pPassword->Length);
|
|
|
|
pStringBuffer += pSession->pPassword->Length;
|
|
|
|
SmbPutUshort(pStringBuffer, L'\0');
|
|
pStringBuffer += sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
RxDbgTrace(0,Dbg,("KerberosResponsePrologue: Acquiring Credential handle\n"));
|
|
RtlInitUnicodeString(&KerberosName, NEGOSSP_NAME_W);
|
|
|
|
SecStatus = AcquireCredentialsHandleW(
|
|
NULL,
|
|
&KerberosName,
|
|
SECPKG_CRED_OUTBOUND,
|
|
&pExtendedSession->LogonId,
|
|
pCredentialBuffer,
|
|
NULL,
|
|
NULL,
|
|
&pExtendedSession->CredentialHandle,
|
|
&LifeTime);
|
|
|
|
Status = MapSecurityError( SecStatus );
|
|
|
|
if ( pCredentialBuffer )
|
|
{
|
|
ExFreePool( pCredentialBuffer );
|
|
pCredentialBuffer = NULL ;
|
|
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
|
|
SecInvalidateHandle( &pExtendedSession->CredentialHandle );
|
|
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildExtendedSessionSetupResponsePrologue_1,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
try_return(Status);
|
|
}
|
|
}
|
|
|
|
if (SecIsValidHandle( &pExtendedSession->SecurityContextHandle) ) {
|
|
pInputContextHandle = &pExtendedSession->SecurityContextHandle;
|
|
}
|
|
|
|
InputToken.pBuffers = &InputBuffer;
|
|
InputToken.cBuffers = 1;
|
|
InputToken.ulVersion = 0;
|
|
InputBuffer.pvBuffer = pServerSecurityBlob;
|
|
InputBuffer.cbBuffer = ServerSecurityBlobSize;
|
|
InputBuffer.BufferType = SECBUFFER_TOKEN;
|
|
|
|
RxDbgTrace(0,Dbg,("ExtendedSessionSetupResponsePrologue: Finished setting up input token\n"));
|
|
|
|
OutputBuffer.pvBuffer = pSecurityBlobPtr ;
|
|
OutputBuffer.cbBuffer = SmbCeGetExchangeServer( pExchange )->MaximumBufferSize ;
|
|
OutputBuffer.cbBuffer -= (sizeof( REQ_SESSION_SETUP_ANDX ) + sizeof( SMB_HEADER ) + 0x80 );
|
|
|
|
ASSERT( OutputBuffer.cbBuffer <= *pSecurityBlobSize );
|
|
|
|
OutputBuffer.BufferType = SECBUFFER_TOKEN;
|
|
OutputBufferSize = OutputBuffer.cbBuffer;
|
|
|
|
OutputToken.pBuffers = &OutputBuffer;
|
|
OutputToken.cBuffers = 1;
|
|
OutputToken.ulVersion = SECBUFFER_VERSION ;
|
|
|
|
if (MRxSmbSecuritySignaturesEnabled) {
|
|
LsaFlags |= ISC_REQ_INTEGRITY;
|
|
}
|
|
|
|
RxDbgTrace(0,Dbg,("ExtendedSessionSetupResponsePrologue: Finished setting up output token\n"));
|
|
|
|
SecStatus = InitializeSecurityContextW(
|
|
&pExtendedSession->CredentialHandle,
|
|
pInputContextHandle,
|
|
&PrincipalName,
|
|
LsaFlags,
|
|
0, // reserved
|
|
SECURITY_NATIVE_DREP,
|
|
&InputToken,
|
|
0, // reserved
|
|
&pExtendedSession->SecurityContextHandle,
|
|
&OutputToken,
|
|
&Catts,
|
|
&Expiry);
|
|
|
|
Status = MapSecurityError( SecStatus );
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// RDR or SRV is sending in a corrupt security blob to LSA -- need to
|
|
// find out what the source is.
|
|
//
|
|
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
if( (OutputBuffer.pvBuffer != NULL) &&
|
|
(OutputBuffer.cbBuffer >= sizeof(DWORD))
|
|
)
|
|
{
|
|
PUCHAR pValidate = (PUCHAR) OutputBuffer.pvBuffer ;
|
|
ASSERT( (pValidate[0] != 0) ||
|
|
(pValidate[1] != 0) ||
|
|
(pValidate[2] != 0) ||
|
|
(pValidate[3] != 0) );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if((Status != STATUS_SUCCESS) &&
|
|
(SecStatus != SEC_I_COMPLETE_NEEDED) &&
|
|
(SecStatus != SEC_I_CONTINUE_NEEDED)) {
|
|
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildExtendedSessionSetupResponsePrologue_2,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
|
|
try_return(Status);
|
|
}
|
|
|
|
if ((SecStatus == SEC_I_COMPLETE_NEEDED) ||
|
|
(SecStatus == SEC_I_CONTINUE_NEEDED)) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (SecStatus == STATUS_SUCCESS) {
|
|
SecPkgContext_SessionKey SecKeys;
|
|
|
|
SecStatus = QueryContextAttributesW(
|
|
&pExtendedSession->SecurityContextHandle,
|
|
SECPKG_ATTR_SESSION_KEY,
|
|
&SecKeys);
|
|
|
|
Status = MapSecurityError( SecStatus );
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
ULONG SessionKeyLength = (MSV1_0_USER_SESSION_KEY_LENGTH >
|
|
SecKeys.SessionKeyLength) ?
|
|
MSV1_0_USER_SESSION_KEY_LENGTH :
|
|
SecKeys.SessionKeyLength;
|
|
RtlZeroMemory(
|
|
(PVOID) pSession->UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
|
|
RtlCopyMemory(
|
|
(PVOID) pSession->UserSessionKey,
|
|
SecKeys.SessionKey,
|
|
SessionKeyLength);
|
|
|
|
pSession->SessionKeyLength = SessionKeyLength;
|
|
|
|
if (SecKeys.SessionKey != NULL) {
|
|
FreeContextBuffer( SecKeys.SessionKey );
|
|
}
|
|
|
|
} else {
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildExtendedSessionSetupResponsePrologue_3,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
}
|
|
|
|
}
|
|
|
|
RxDbgTrace(0,Dbg,("ExtendedSessionSetupResponsePrologue: Initialize security context successful\n"));
|
|
|
|
*pSecurityBlobSize = (USHORT)OutputBuffer.cbBuffer;
|
|
|
|
|
|
try_exit:NOTHING;
|
|
} finally {
|
|
NOTHING ;
|
|
}
|
|
|
|
FINALLY:
|
|
|
|
if(bTempServerName == TRUE) {
|
|
RxFreePool(ServerName.Buffer);
|
|
}
|
|
|
|
if ( PrincipalName.Buffer )
|
|
{
|
|
ExFreePool( PrincipalName.Buffer );
|
|
}
|
|
|
|
if ((Status != STATUS_SUCCESS) &&
|
|
(Status != STATUS_WRONG_PASSWORD) &&
|
|
(Status != STATUS_MORE_PROCESSING_REQUIRED)) {
|
|
/*
|
|
if (!pServer->EventLogPosted) {
|
|
RxLogFailure(
|
|
MRxSmbDeviceObject,
|
|
NULL,
|
|
EVENT_RDR_CANT_GET_SECURITY_CONTEXT,
|
|
Status);
|
|
|
|
pServer->EventLogPosted = TRUE;
|
|
} */
|
|
|
|
SmbCeLog(("KerbProlg %lx Status %lx\n",SmbCeGetExchangeSessionEntry(pExchange),Status));
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildExtendedSessionSetupResponsePrologue,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
BuildExtendedSessionSetupResponseEpilogue(
|
|
PSECURITY_RESPONSE_CONTEXT pResponseContext)
|
|
{
|
|
ULONG_PTR Zero = 0 ;
|
|
PAGED_CODE();
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ValidateServerExtendedSessionSetupResponse(
|
|
PSMB_EXTENDED_SESSION_SETUP_EXCHANGE pExtendedSessionSetupExchange,
|
|
PVOID pServerResponseBlob,
|
|
ULONG ServerResponseBlobLength)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds the security related information for the session setup SMB to
|
|
a server with extended security negotiation
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
Eventhough the genral structure of the code tries to isolate dialect specific issues
|
|
as much as possible this routine takes the opposite approach. This is because of the
|
|
preamble and prologue to security interaction which far outweigh the dialect specific
|
|
work required to be done. Therefore in the interests of a smaller footprint this approach
|
|
has been adopted.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SECURITY_STATUS SecStatus;
|
|
|
|
ULONG Catts = 0;
|
|
TimeStamp Expiry;
|
|
|
|
ULONG LsaFlags = ISC_REQ_MUTUAL_AUTH | ISC_REQ_ALLOCATE_MEMORY;
|
|
|
|
UNICODE_STRING PrincipalName;
|
|
PUNICODE_STRING pServerPrincipalName;
|
|
|
|
PUCHAR pTempBlob = NULL;
|
|
|
|
PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExtendedSessionSetupExchange);
|
|
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExtendedSessionSetupExchange);
|
|
|
|
UNICODE_STRING ServerName;
|
|
PUNICODE_STRING pServerDomainName;
|
|
|
|
PSMBCE_EXTENDED_SESSION pExtendedSession;
|
|
|
|
SecBufferDesc InputToken;
|
|
SecBuffer InputBuffer;
|
|
SecBufferDesc OutputToken;
|
|
SecBuffer OutputBuffer;
|
|
|
|
SecPkgContext_SessionKey SecKeys;
|
|
|
|
KAPC_STATE ApcState;
|
|
BOOLEAN AttachToSystemProcess = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT((pExtendedSessionSetupExchange->Type == EXTENDED_SESSION_SETUP_EXCHANGE) &&
|
|
(pSession->Type == EXTENDED_NT_SESSION));
|
|
|
|
|
|
SecKeys.SessionKey = NULL;
|
|
|
|
pExtendedSession = (PSMBCE_EXTENDED_SESSION)pSession;
|
|
|
|
if (pExtendedSession == NULL ||
|
|
!SecIsValidHandle(&pExtendedSession->CredentialHandle)) {
|
|
return STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
SmbCeGetServerName(
|
|
pExtendedSessionSetupExchange->SmbCeContext.pVNetRoot->pNetRoot->pSrvCall,&ServerName);
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
RxDbgTrace(0,Dbg,("ValidateServerResponse: Blob Length %ld\n",pExtendedSessionSetupExchange->ServerResponseBlobLength));
|
|
|
|
InputToken.pBuffers = &InputBuffer;
|
|
InputToken.cBuffers = 1;
|
|
InputToken.ulVersion = 0;
|
|
InputBuffer.pvBuffer = pServerResponseBlob ;
|
|
InputBuffer.cbBuffer = pExtendedSessionSetupExchange->ServerResponseBlobLength;
|
|
InputBuffer.BufferType = SECBUFFER_TOKEN;
|
|
|
|
RxDbgTrace(0,Dbg,("ValidateKerberosServerResponse: filled in input token\n"));
|
|
|
|
OutputToken.pBuffers = &OutputBuffer;
|
|
OutputToken.cBuffers = 1;
|
|
OutputToken.ulVersion = 0;
|
|
OutputBuffer.pvBuffer = NULL;
|
|
OutputBuffer.cbBuffer = 0;
|
|
OutputBuffer.BufferType = SECBUFFER_TOKEN;
|
|
|
|
RxDbgTrace(0,Dbg,("ValidateKerberosServerResponse: filled in output token\n"));
|
|
|
|
SecStatus = InitializeSecurityContextW(
|
|
&pExtendedSession->CredentialHandle,
|
|
&pExtendedSession->SecurityContextHandle,
|
|
NULL,
|
|
LsaFlags,
|
|
0, // reserved
|
|
SECURITY_NATIVE_DREP,
|
|
&InputToken,
|
|
0, // reserved
|
|
&pExtendedSession->SecurityContextHandle,
|
|
&OutputToken,
|
|
&Catts,
|
|
&Expiry);
|
|
|
|
Status = MapSecurityError( SecStatus );
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// RDR or SRV is sending in a corrupt security blob to LSA -- need to
|
|
// find out what the source is.
|
|
//
|
|
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
if( (OutputBuffer.pvBuffer != NULL) &&
|
|
(OutputBuffer.cbBuffer >= sizeof(DWORD))
|
|
)
|
|
{
|
|
ASSERT( NT_SUCCESS( KSecValidateBuffer( OutputBuffer.pvBuffer, OutputBuffer.cbBuffer ) ) );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if((Status != STATUS_SUCCESS) &&
|
|
(SecStatus != SEC_I_COMPLETE_NEEDED) &&
|
|
(SecStatus != SEC_I_CONTINUE_NEEDED)) {
|
|
SmbLogError(Status,
|
|
LOG,
|
|
ValidateServerExtendedSessionSetupResponse_1,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
try_return(Status);
|
|
}
|
|
|
|
if ((SecStatus == SEC_I_COMPLETE_NEEDED) ||
|
|
(SecStatus == SEC_I_CONTINUE_NEEDED)) {
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
SecStatus = QueryContextAttributesW(
|
|
&pExtendedSession->SecurityContextHandle,
|
|
SECPKG_ATTR_SESSION_KEY,
|
|
&SecKeys);
|
|
|
|
Status = MapSecurityError( SecStatus );
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
ULONG SessionKeyLength = (MSV1_0_USER_SESSION_KEY_LENGTH >
|
|
SecKeys.SessionKeyLength) ?
|
|
MSV1_0_USER_SESSION_KEY_LENGTH :
|
|
SecKeys.SessionKeyLength;
|
|
RtlZeroMemory(
|
|
(PVOID) pSession->UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
|
|
RtlCopyMemory(
|
|
(PVOID) pSession->UserSessionKey,
|
|
SecKeys.SessionKey,
|
|
SessionKeyLength);
|
|
|
|
pSession->SessionKeyLength = SessionKeyLength;
|
|
} else {
|
|
SmbLogError(Status,
|
|
LOG,
|
|
ValidateServerExtendedSessionSetupResponse_2,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
}
|
|
|
|
if (SecKeys.SessionKey != NULL) {
|
|
FreeContextBuffer( SecKeys.SessionKey );
|
|
}
|
|
}
|
|
|
|
RxDbgTrace(0,Dbg,("ValidateKerberosServerResponse: SecuritContext returned %ld\n",Status));
|
|
|
|
if (OutputBuffer.pvBuffer != NULL) {
|
|
FreeContextBuffer(OutputBuffer.pvBuffer);
|
|
}
|
|
|
|
try_exit:NOTHING;
|
|
} finally {
|
|
|
|
NOTHING ;
|
|
}
|
|
|
|
if ((Status != STATUS_SUCCESS) &&
|
|
(Status != STATUS_WRONG_PASSWORD) &&
|
|
(Status != STATUS_MORE_PROCESSING_REQUIRED)) {
|
|
/*
|
|
if (!pServer->EventLogPosted) {
|
|
RxLogFailure(
|
|
MRxSmbDeviceObject,
|
|
NULL,
|
|
EVENT_RDR_CANT_GET_SECURITY_CONTEXT,
|
|
Status);
|
|
|
|
pServer->EventLogPosted = TRUE;
|
|
} */
|
|
|
|
SmbCeLog((
|
|
"ValServer %lx Status %lx\n",
|
|
SmbCeGetExchangeSessionEntry(
|
|
(PSMB_EXCHANGE)pExtendedSessionSetupExchange),
|
|
Status));
|
|
SmbLogError(Status,
|
|
LOG,
|
|
ValidateServerExtendedSessionSetupResponse,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status));
|
|
}
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
UninitializeSecurityContextsForSession(
|
|
PSMBCE_SESSION pSession)
|
|
{
|
|
CtxtHandle CredentialHandle,SecurityContextHandle ;
|
|
|
|
SmbCeLog(("UninitSecCont %lx\n",pSession));
|
|
SmbLog(LOG,
|
|
UninitializeSecurityContextsForSession,
|
|
LOGPTR(pSession));
|
|
|
|
|
|
SmbCeAcquireSpinLock();
|
|
|
|
CredentialHandle = pSession->CredentialHandle;
|
|
SecInvalidateHandle( &pSession->CredentialHandle );
|
|
|
|
SecurityContextHandle = pSession->SecurityContextHandle;
|
|
SecInvalidateHandle( &pSession->SecurityContextHandle );
|
|
|
|
SmbCeReleaseSpinLock();
|
|
|
|
if (SecIsValidHandle(&CredentialHandle)) {
|
|
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) ||
|
|
MRxSmbUseKernelModeSecurity) {
|
|
FreeCredentialsHandleK(&CredentialHandle);
|
|
} else {
|
|
FreeCredentialsHandle(&CredentialHandle);
|
|
}
|
|
}
|
|
|
|
if (SecIsValidHandle(&SecurityContextHandle)) {
|
|
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) ||
|
|
MRxSmbUseKernelModeSecurity) {
|
|
DeleteSecurityContextK(&SecurityContextHandle);
|
|
} else {
|
|
DeleteSecurityContext(&SecurityContextHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DeleteSecurityContextForSession(
|
|
PSMBCE_SESSION pSession)
|
|
{
|
|
CtxtHandle SecurityContextHandle ;
|
|
|
|
SmbCeLog(("DelSecContext %lx\n",pSession));
|
|
SmbLog(LOG,
|
|
DeleteSecurityContextForSession,
|
|
LOGPTR(pSession));
|
|
|
|
SmbCeAcquireSpinLock();
|
|
|
|
SecurityContextHandle = pSession->SecurityContextHandle;
|
|
SecInvalidateHandle( &pSession->SecurityContextHandle);
|
|
|
|
SmbCeReleaseSpinLock();
|
|
|
|
if (SecIsValidHandle(&SecurityContextHandle)) {
|
|
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) ||
|
|
MRxSmbUseKernelModeSecurity) {
|
|
DeleteSecurityContextK(&SecurityContextHandle);
|
|
} else {
|
|
DeleteSecurityContext(&SecurityContextHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BuildExtendedSessionSetupResponsePrologueFake(
|
|
PSMB_EXCHANGE pExchange)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds the security related information for the session setup SMB to
|
|
a NT server with extended security
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
Eventhough the genral structure of the code tries to isolate dialect specific issues
|
|
as much as possible this routine takes the opposite approach. This is because of the
|
|
preamble and prologue to security interaction which far outweigh the dialect specific
|
|
work required to be done. Therefore in the interests of a smaller footprint this approach
|
|
has been adopted.
|
|
|
|
This routine needs to be executed in the system process in order to protect virtual memory
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SECURITY_STATUS SecStatus;
|
|
|
|
TimeStamp Expiry;
|
|
ULONG Catts = ISC_RET_MUTUAL_AUTH;
|
|
ULONG LsaFlags = (ISC_REQ_DELEGATE |
|
|
ISC_REQ_MUTUAL_AUTH |
|
|
ISC_REQ_FRAGMENT_TO_FIT);
|
|
|
|
ULONG_PTR RegionSize = 0;
|
|
ULONG_PTR OutputBufferSize;
|
|
|
|
UNICODE_STRING PrincipalName;
|
|
PUNICODE_STRING pServerPrincipalName;
|
|
|
|
PVOID pServerSecurityBlob;
|
|
ULONG ServerSecurityBlobSize;
|
|
|
|
PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
|
|
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
|
|
|
UNICODE_STRING ServerName;
|
|
PUNICODE_STRING pServerDomainName;
|
|
|
|
SMBCE_EXTENDED_SESSION ExtendedSession;
|
|
|
|
SecBufferDesc InputToken;
|
|
SecBuffer InputBuffer = { 0 };
|
|
SecBufferDesc OutputToken;
|
|
SecBuffer OutputBuffer = { 0 };
|
|
|
|
PCtxtHandle pInputContextHandle = NULL;
|
|
|
|
SecPkgContext_NegotiationInfoW NegInfo = { 0 };
|
|
|
|
PAGED_CODE();
|
|
|
|
SmbCeGetServerName(
|
|
pExchange->SmbCeContext.pVNetRoot->pNetRoot->pSrvCall,
|
|
&ServerName);
|
|
|
|
ASSERT(ServerName.MaximumLength > (ServerName.Length + sizeof(WCHAR)));
|
|
|
|
ExtendedSession.Flags = pSession->Flags;
|
|
ExtendedSession.LogonId = pSession->LogonId;
|
|
SecInvalidateHandle( &ExtendedSession.CredentialHandle );
|
|
SecInvalidateHandle( &ExtendedSession.SecurityContextHandle );
|
|
|
|
pServerPrincipalName = pExchange->SmbCeContext.pVNetRoot->pNetRoot->pSrvCall->pPrincipalName;
|
|
|
|
|
|
ServerSecurityBlobSize = 0; //there is no security blob in case of NTLM
|
|
pServerSecurityBlob = NULL;
|
|
|
|
try {
|
|
UNICODE_STRING KerberosName;
|
|
TimeStamp LifeTime;
|
|
|
|
ULONG_PTR CredentialBufferLength;
|
|
PSEC_WINNT_AUTH_IDENTITY_EXW pCredentialBuffer;
|
|
|
|
PBYTE pStringBuffer;
|
|
|
|
|
|
|
|
CredentialBufferLength = 0;
|
|
pCredentialBuffer = NULL;
|
|
|
|
if(pSession->pUserName != NULL) {
|
|
CredentialBufferLength += pSession->pUserName->Length + sizeof(WCHAR);
|
|
}
|
|
|
|
if (pSession->pUserDomainName != NULL) {
|
|
CredentialBufferLength += pSession->pUserDomainName->Length + sizeof(WCHAR);
|
|
}
|
|
|
|
if(pSession->pPassword != NULL) {
|
|
CredentialBufferLength += pSession->pPassword->Length + sizeof(WCHAR);
|
|
}
|
|
|
|
if (CredentialBufferLength != 0) {
|
|
|
|
CredentialBufferLength += sizeof(SEC_WINNT_AUTH_IDENTITY_EXW);
|
|
|
|
pCredentialBuffer = (PSEC_WINNT_AUTH_IDENTITY_EXW) ExAllocatePool(
|
|
PagedPool,
|
|
CredentialBufferLength );
|
|
|
|
if ( !pCredentialBuffer )
|
|
{
|
|
Status = STATUS_NO_MEMORY ;
|
|
try_return( Status );
|
|
|
|
}
|
|
//
|
|
// Zero the fixed portion
|
|
//
|
|
RtlZeroMemory( pCredentialBuffer, sizeof( SEC_WINNT_AUTH_IDENTITY_EXW ));
|
|
|
|
pCredentialBuffer->Version = SEC_WINNT_AUTH_IDENTITY_VERSION ;
|
|
pCredentialBuffer->Length = sizeof( SEC_WINNT_AUTH_IDENTITY_EXW );
|
|
pCredentialBuffer->Flags = (SEC_WINNT_AUTH_IDENTITY_UNICODE |
|
|
SEC_WINNT_AUTH_IDENTITY_MARSHALLED);
|
|
|
|
|
|
pStringBuffer = (PBYTE)( pCredentialBuffer + 1 );
|
|
|
|
if (pSession->pUserName != NULL) {
|
|
pCredentialBuffer->UserLength = pSession->pUserName->Length / sizeof(WCHAR);
|
|
pCredentialBuffer->User = (PWCHAR)pStringBuffer;
|
|
|
|
RtlCopyMemory(
|
|
pCredentialBuffer->User,
|
|
pSession->pUserName->Buffer,
|
|
pSession->pUserName->Length);
|
|
|
|
pStringBuffer += pSession->pUserName->Length;
|
|
|
|
SmbPutUshort(pStringBuffer,L'\0');
|
|
pStringBuffer += sizeof(WCHAR);
|
|
}
|
|
|
|
if (pSession->pUserDomainName != NULL) {
|
|
pCredentialBuffer->DomainLength = pSession->pUserDomainName->Length / sizeof(WCHAR);
|
|
pCredentialBuffer->Domain = (PWCHAR)pStringBuffer;
|
|
|
|
RtlCopyMemory(
|
|
pCredentialBuffer->Domain,
|
|
pSession->pUserDomainName->Buffer,
|
|
pSession->pUserDomainName->Length);
|
|
|
|
pStringBuffer += pSession->pUserDomainName->Length;
|
|
|
|
SmbPutUshort(pStringBuffer,L'\0');
|
|
pStringBuffer += sizeof(WCHAR);
|
|
}
|
|
|
|
if (pSession->pPassword != NULL) {
|
|
pCredentialBuffer->PasswordLength = pSession->pPassword->Length / sizeof(WCHAR);
|
|
pCredentialBuffer->Password = (PWCHAR)pStringBuffer;
|
|
|
|
RtlCopyMemory(
|
|
pCredentialBuffer->Password,
|
|
pSession->pPassword->Buffer,
|
|
pSession->pPassword->Length);
|
|
|
|
pStringBuffer += pSession->pPassword->Length;
|
|
|
|
SmbPutUshort(pStringBuffer, L'\0');
|
|
pStringBuffer += sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
RxDbgTrace(0,Dbg,("KerberosResponsePrologue: Acquiring Credential handle\n"));
|
|
RtlInitUnicodeString(&KerberosName, NEGOSSP_NAME_W);
|
|
|
|
SecStatus = AcquireCredentialsHandleW(
|
|
NULL,
|
|
&KerberosName,
|
|
SECPKG_CRED_OUTBOUND,
|
|
&ExtendedSession.LogonId,
|
|
pCredentialBuffer,
|
|
NULL,
|
|
NULL,
|
|
&ExtendedSession.CredentialHandle,
|
|
&LifeTime);
|
|
|
|
Status = MapSecurityError( SecStatus );
|
|
|
|
if (pCredentialBuffer != NULL) {
|
|
|
|
ExFreePool( pCredentialBuffer );
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
SecInvalidateHandle( &ExtendedSession.CredentialHandle );
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildExtendedSessionSetupResponsePrologueFake_1,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
try_return(Status);
|
|
}
|
|
|
|
|
|
Status = SecMakeSPN(
|
|
&CifsServiceName,
|
|
&ServerName,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&PrincipalName,
|
|
NULL,
|
|
TRUE );
|
|
|
|
|
|
InputToken.pBuffers = &InputBuffer;
|
|
InputToken.cBuffers = 1;
|
|
InputToken.ulVersion = 0;
|
|
InputBuffer.pvBuffer = pServerSecurityBlob;
|
|
InputBuffer.cbBuffer = ServerSecurityBlobSize;
|
|
InputBuffer.BufferType = SECBUFFER_TOKEN;
|
|
|
|
OutputBuffer.pvBuffer = NULL;
|
|
OutputBuffer.cbBuffer = SmbCeGetExchangeServer( pExchange )->MaximumBufferSize;
|
|
OutputBuffer.cbBuffer -= (sizeof( REQ_SESSION_SETUP_ANDX ) + sizeof( SMB_HEADER ) + 0x80 );
|
|
OutputBuffer.BufferType = SECBUFFER_TOKEN;
|
|
OutputBufferSize = OutputBuffer.cbBuffer;
|
|
|
|
OutputBuffer.pvBuffer = ExAllocatePool( PagedPool, OutputBufferSize );
|
|
|
|
if ( OutputBuffer.pvBuffer == NULL )
|
|
{
|
|
Status = STATUS_NO_MEMORY ;
|
|
try_return( Status );
|
|
|
|
}
|
|
|
|
OutputToken.pBuffers = &OutputBuffer;
|
|
OutputToken.cBuffers = 1;
|
|
OutputToken.ulVersion = SECBUFFER_VERSION ;
|
|
|
|
if (pServerEntry->Server.SecurityMode == SECURITY_MODE_SHARE_LEVEL)
|
|
{
|
|
LsaFlags |= ISC_REQ_USE_SUPPLIED_CREDS;
|
|
}
|
|
|
|
SecStatus = InitializeSecurityContextW(
|
|
&ExtendedSession.CredentialHandle,
|
|
pInputContextHandle,
|
|
&PrincipalName,
|
|
LsaFlags,
|
|
0, // reserved
|
|
SECURITY_NATIVE_DREP,
|
|
&InputToken,
|
|
0, // reserved
|
|
&ExtendedSession.SecurityContextHandle,
|
|
&OutputToken,
|
|
&Catts,
|
|
&Expiry);
|
|
|
|
Status = MapSecurityError( SecStatus );
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// RDR or SRV is sending in a corrupt security blob to LSA -- need to
|
|
// find out what the source is.
|
|
//
|
|
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
if( (OutputBuffer.pvBuffer != NULL) &&
|
|
(OutputBuffer.cbBuffer >= sizeof(DWORD))
|
|
)
|
|
{
|
|
ASSERT( NT_SUCCESS( KSecValidateBuffer( OutputBuffer.pvBuffer, OutputBuffer.cbBuffer ) ) );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if((Status != STATUS_SUCCESS) &&
|
|
(SecStatus != SEC_I_COMPLETE_NEEDED) &&
|
|
(SecStatus != SEC_I_CONTINUE_NEEDED)) {
|
|
|
|
RxLog(("ISC returned %lx\n",Status));
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildExtendedSessionSetupResponsePrologueFake_2,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
try_return(Status);
|
|
}
|
|
|
|
SecStatus = QueryContextAttributesW(
|
|
&ExtendedSession.SecurityContextHandle,
|
|
SECPKG_ATTR_NEGOTIATION_INFO,
|
|
&NegInfo);
|
|
|
|
Status = MapSecurityError( SecStatus );
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxLog(("QCA returned %lx\n",Status));
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildExtendedSessionSetupResponsePrologueFake_3,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
}
|
|
|
|
try_exit:NOTHING;
|
|
} finally {
|
|
if (Status == STATUS_SUCCESS) {
|
|
|
|
if (NegInfo.PackageInfo->wRPCID != NTLMSP_RPCID) {
|
|
Status = STATUS_LOGIN_WKSTA_RESTRICTION;
|
|
|
|
//RxLogFailure(
|
|
// MRxSmbDeviceObject,
|
|
// NULL,
|
|
// EVENT_RDR_ENCOUNTER_DOWNGRADE_ATTACK,
|
|
// Status);
|
|
|
|
RxLog(("NTLM downgrade attack from %wZ\n",&pServerEntry->Name));
|
|
#if DBG
|
|
DbgPrint("NTLM downgrade attack from %wZ\n",&pServerEntry->Name);
|
|
#endif
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildExtendedSessionSetupResponsePrologueFake_4,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status)
|
|
LOGUSTR(ServerName));
|
|
}
|
|
}
|
|
|
|
UninitializeSecurityContextsForSession((PSMBCE_SESSION)(&ExtendedSession));
|
|
|
|
if ( NegInfo.PackageInfo != NULL) {
|
|
FreeContextBuffer(NegInfo.PackageInfo);
|
|
}
|
|
|
|
if (OutputBuffer.pvBuffer != NULL) {
|
|
ExFreePool( OutputBuffer.pvBuffer );
|
|
}
|
|
|
|
|
|
SmbLogError(Status,
|
|
LOG,
|
|
BuildExtendedSessionSetupResponsePrologueFake,
|
|
LOGPTR(pSession)
|
|
LOGULONG(Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|