972 lines
35 KiB
C
972 lines
35 KiB
C
/*++
|
||
Copyright (c) 1987-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
sessetup.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the Session setup related routines
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
#include "ntlmsp.h"
|
||
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_DISPATCH)
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, BuildSessionSetupSmb)
|
||
#pragma alloc_text(PAGE, BuildNtLanmanResponsePrologue)
|
||
#pragma alloc_text(PAGE, BuildNtLanmanResponseEpilogue)
|
||
#pragma alloc_text(PAGE, BuildSessionSetupSecurityInformation)
|
||
#pragma alloc_text(PAGE, BuildTreeConnectSecurityInformation)
|
||
#endif
|
||
|
||
BOOLEAN EnablePlainTextPassword = FALSE;
|
||
|
||
|
||
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;
|
||
|
||
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. This implies that
|
||
// great care must be taken in shuffling the fields in these two structs.
|
||
|
||
pSessionSetup = (PREQ_SESSION_SETUP_ANDX)pAndXSmb;
|
||
pNtSessionSetup = (PREQ_NT_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.
|
||
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) {
|
||
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;
|
||
}
|
||
|
||
|
||
#define IsCredentialHandleValid(pCredHandle) \
|
||
(((pCredHandle)->dwLower != 0xffffffff) && ((pCredHandle)->dwUpper != 0xffffffff))
|
||
|
||
#define IsSecurityContextHandleValid(pContextHandle) \
|
||
(((pContextHandle)->dwLower != 0xffffffff) && ((pContextHandle)->dwUpper != 0xffffffff))
|
||
|
||
|
||
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.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - The return status for the operation
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
NTSTATUS FinalStatus;
|
||
|
||
UNICODE_STRING ServerName;
|
||
|
||
PVOID pTargetInformation;
|
||
ULONG TargetInformationSize;
|
||
|
||
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);
|
||
|
||
PAGED_CODE();
|
||
|
||
try {
|
||
pResponseContext->LanmanSetup.pResponseBuffer = NULL;
|
||
|
||
SmbCeGetServerName(
|
||
pExchange->SmbCeContext.pVNetRoot->pNetRoot->pSrvCall,
|
||
&ServerName);
|
||
|
||
TargetInformationSize = ServerName.Length;
|
||
pTargetInformation = ServerName.Buffer;
|
||
|
||
InTokenSize = sizeof(CHALLENGE_MESSAGE) + TargetInformationSize;
|
||
|
||
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;
|
||
|
||
Status = ZwAllocateVirtualMemory(
|
||
NtCurrentProcess(),
|
||
&InToken,
|
||
0L,
|
||
&AllocateSize,
|
||
MEM_COMMIT,
|
||
PAGE_READWRITE);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
try_return(Status);
|
||
}
|
||
|
||
// Allocate the output buffer
|
||
OutputBufferDescriptorSize = sizeof(SecBufferDesc) + 2 * sizeof(SecBuffer);
|
||
|
||
Status = ZwAllocateVirtualMemory(
|
||
NtCurrentProcess(),
|
||
&pOutputBufferDescriptor,
|
||
0L,
|
||
&OutputBufferDescriptorSize,
|
||
MEM_COMMIT,
|
||
PAGE_READWRITE);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
try_return(Status);
|
||
}
|
||
|
||
pOutputBuffer = (SecBuffer *)(pOutputBufferDescriptor + 1);
|
||
pResponseContext->LanmanSetup.pResponseBuffer = pOutputBufferDescriptor;
|
||
|
||
RxDbgTrace(0,Dbg,("Allocate VM %08lx in process %8lx\n", InToken, NtCurrentProcess()));
|
||
|
||
// 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(!IsCredentialHandleValid(&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);
|
||
|
||
|
||
Status = AcquireCredentialsHandleW(
|
||
NULL,
|
||
&LMName,
|
||
SECPKG_CRED_OUTBOUND,
|
||
&pSession->LogonId,
|
||
NULL,
|
||
NULL,
|
||
(PVOID)1,
|
||
&pSession->CredentialHandle,
|
||
&LifeTime);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
pSession->CredentialHandle.dwUpper = 0xffffffff;
|
||
pSession->CredentialHandle.dwLower = 0xffffffff;
|
||
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 |
|
||
NTLMSSP_TARGET_TYPE_SERVER;
|
||
|
||
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);
|
||
|
||
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;
|
||
|
||
Status = InitializeSecurityContextW(
|
||
&pSession->CredentialHandle,
|
||
(PCtxtHandle)NULL,
|
||
NULL,
|
||
LsaFlags,
|
||
0,
|
||
SECURITY_NATIVE_DREP,
|
||
&InputToken,
|
||
0,
|
||
&pSession->SecurityContextHandle,
|
||
pOutputBufferDescriptor,
|
||
&FinalStatus,
|
||
&Expiry);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
Status = MapSecurityError(Status);
|
||
SmbCeLog(("IniSecCtxStat %lx %lx\n",SmbCeGetExchangeSessionEntry(pExchange),Status));
|
||
try_return(Status);
|
||
}
|
||
|
||
OutToken = (PAUTHENTICATE_MESSAGE) pOutputBuffer[0].pvBuffer;
|
||
|
||
ASSERT(OutToken != NULL);
|
||
RxDbgTrace(0,Dbg,("InitSecCtxt OutToken is %8lx\n", OutToken));
|
||
|
||
// 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) {
|
||
NTSTATUS TemporaryStatus;
|
||
|
||
TemporaryStatus = ZwFreeVirtualMemory(
|
||
NtCurrentProcess(),
|
||
&InToken,
|
||
&AllocateSize,
|
||
MEM_RELEASE);
|
||
|
||
ASSERT (NT_SUCCESS(TemporaryStatus));
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
BuildNtLanmanResponseEpilogue(pExchange, pResponseContext);
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
BuildNtLanmanResponseEpilogue(
|
||
PSMB_EXCHANGE pExchange,
|
||
PSECURITY_RESPONSE_CONTEXT pResponseContext)
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
|
||
|
||
PAGED_CODE();
|
||
|
||
if (pResponseContext->LanmanSetup.pResponseBuffer != NULL) {
|
||
ULONG i = 0;
|
||
SecBufferDesc *pBufferDescriptor = (SecBufferDesc *)pResponseContext->LanmanSetup.pResponseBuffer;
|
||
SecBuffer *pBuffer = pBufferDescriptor->pBuffers;
|
||
ULONG_PTR BufferDescriptorSize = sizeof(SecBufferDesc) + 2 * sizeof(SecBuffer);
|
||
|
||
for (i = 0; i < pBufferDescriptor->cBuffers; i++) {
|
||
if (pBuffer[i].pvBuffer != NULL) {
|
||
FreeContextBuffer(pBuffer[i].pvBuffer);
|
||
}
|
||
}
|
||
|
||
Status = ZwFreeVirtualMemory(
|
||
NtCurrentProcess(),
|
||
&pBufferDescriptor,
|
||
&BufferDescriptorSize,
|
||
MEM_RELEASE);
|
||
|
||
pResponseContext->LanmanSetup.pResponseBuffer = NULL;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
VOID
|
||
UninitializeSecurityContextsForSession(
|
||
PSMBCE_SESSION pSession)
|
||
{
|
||
CtxtHandle CredentialHandle,SecurityContextHandle,InvalidHandle;
|
||
|
||
SmbCeLog(("UninitSecCont %lx\n",pSession));
|
||
|
||
InvalidHandle.dwUpper = 0xffffffff;
|
||
InvalidHandle.dwLower = 0xffffffff;
|
||
|
||
SmbCeAcquireSpinLock();
|
||
|
||
CredentialHandle = pSession->CredentialHandle;
|
||
pSession->CredentialHandle = InvalidHandle;
|
||
|
||
SecurityContextHandle = pSession->SecurityContextHandle;
|
||
pSession->SecurityContextHandle = InvalidHandle;
|
||
|
||
SmbCeReleaseSpinLock();
|
||
|
||
if (IsCredentialHandleValid(&CredentialHandle))
|
||
{
|
||
FreeCredentialsHandle(&CredentialHandle);
|
||
}
|
||
|
||
if (IsSecurityContextHandleValid(&SecurityContextHandle)) {
|
||
DeleteSecurityContext(&SecurityContextHandle);
|
||
}
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
BuildSessionSetupSecurityInformation(
|
||
PSMB_EXCHANGE pExchange,
|
||
PBYTE pSmbBuffer,
|
||
PULONG pSmbBufferSize)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine builds the security related information for the session setup SMB
|
||
|
||
Arguments:
|
||
|
||
pServer - the server instance
|
||
|
||
pSmbBuffer - the SMB buffer
|
||
|
||
pSmbBufferSize - the size of the buffer on input ( modified to size remaining on
|
||
output)
|
||
|
||
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;
|
||
|
||
UNICODE_STRING UserName;
|
||
UNICODE_STRING DomainName;
|
||
|
||
STRING CaseSensitiveResponse;
|
||
STRING CaseInsensitiveResponse;
|
||
|
||
PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
|
||
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
|
||
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
||
|
||
SECURITY_RESPONSE_CONTEXT ResponseContext;
|
||
|
||
PAGED_CODE();
|
||
RxDbgTrace( +1, Dbg, ("BuildSessionSetupSecurityInformation -- Entry\n"));
|
||
|
||
|
||
Status = BuildNtLanmanResponsePrologue(
|
||
pExchange,
|
||
&UserName,
|
||
&DomainName,
|
||
&CaseSensitiveResponse,
|
||
&CaseInsensitiveResponse,
|
||
&ResponseContext);
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
// If the security package returns us the credentials corresponding to a
|
||
// NULL session mark the session as a NULL session. This will avoid
|
||
// conflicts with the user trying to present the credentials for a NULL
|
||
// session, i.e., explicitly specified zero length passwords, user name
|
||
// and domain name.
|
||
|
||
RxDbgTrace(0,Dbg,("Session %lx UN Length %lx DN length %ld IR length %ld SR length %ld\n",
|
||
pSession,UserName.Length,DomainName.Length,
|
||
CaseInsensitiveResponse.Length,CaseSensitiveResponse.Length));
|
||
|
||
if ((UserName.Length == 0) &&
|
||
(DomainName.Length == 0) &&
|
||
(CaseSensitiveResponse.Length == 0) &&
|
||
(CaseInsensitiveResponse.Length == 1)) {
|
||
RxDbgTrace(0,Dbg,("Implicit NULL session setup\n"));
|
||
pSession->Flags |= SMBCE_SESSION_FLAGS_NULL_CREDENTIALS;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
PBYTE pBuffer = pSmbBuffer;
|
||
ULONG BufferSize = *pSmbBufferSize;
|
||
|
||
if ((pServer->Dialect == NTLANMAN_DIALECT) && (pServer->EncryptPasswords)) {
|
||
PREQ_NT_SESSION_SETUP_ANDX pNtSessionSetupReq = (PREQ_NT_SESSION_SETUP_ANDX)pSmbBuffer;
|
||
|
||
// It it is a NT server both the case insensitive and case sensitive passwords
|
||
// need to be copied. for share-level, just copy a token 1-byte NULL password
|
||
|
||
// Position the buffer for copying the password.
|
||
pBuffer += FIELD_OFFSET(REQ_NT_SESSION_SETUP_ANDX,Buffer);
|
||
BufferSize -= FIELD_OFFSET(REQ_NT_SESSION_SETUP_ANDX,Buffer);
|
||
|
||
if (pServer->SecurityMode == SECURITY_MODE_USER_LEVEL){
|
||
|
||
RxDbgTrace( 0, Dbg, ("BuildSessionSetupSecurityInformation -- NtUserPasswords\n"));
|
||
|
||
SmbPutUshort(
|
||
&pNtSessionSetupReq->CaseInsensitivePasswordLength,
|
||
CaseInsensitiveResponse.Length);
|
||
|
||
SmbPutUshort(
|
||
&pNtSessionSetupReq->CaseSensitivePasswordLength,
|
||
CaseSensitiveResponse.Length);
|
||
|
||
Status = SmbPutString(
|
||
&pBuffer,
|
||
&CaseInsensitiveResponse,
|
||
&BufferSize);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
Status = SmbPutString(
|
||
&pBuffer,
|
||
&CaseSensitiveResponse,
|
||
&BufferSize);
|
||
}
|
||
} else {
|
||
|
||
RxDbgTrace( 0, Dbg, ("BuildSessionSetupSecurityInformation -- NtSharePasswords\n"));
|
||
|
||
SmbPutUshort(&pNtSessionSetupReq->CaseInsensitivePasswordLength, 1);
|
||
SmbPutUshort(&pNtSessionSetupReq->CaseSensitivePasswordLength, 1);
|
||
*pBuffer = 0;
|
||
*(pBuffer+1) = 0;
|
||
pBuffer += 2;
|
||
BufferSize -= 2;
|
||
}
|
||
} else {
|
||
PREQ_SESSION_SETUP_ANDX pSessionSetupReq = (PREQ_SESSION_SETUP_ANDX)pSmbBuffer;
|
||
|
||
// Position the buffer for copying the password.
|
||
pBuffer += FIELD_OFFSET(REQ_SESSION_SETUP_ANDX,Buffer);
|
||
BufferSize -= FIELD_OFFSET(REQ_SESSION_SETUP_ANDX,Buffer);
|
||
|
||
if ( (pServer->SecurityMode == SECURITY_MODE_USER_LEVEL)
|
||
&& (CaseInsensitiveResponse.Length > 0)) {
|
||
|
||
if (pServer->EncryptPasswords) {
|
||
// For other lanman servers only the case insensitive password is required.
|
||
SmbPutUshort(
|
||
&pSessionSetupReq->PasswordLength,
|
||
CaseInsensitiveResponse.Length);
|
||
|
||
// Copy the password
|
||
Status = SmbPutString(
|
||
&pBuffer,
|
||
&CaseInsensitiveResponse,
|
||
&BufferSize);
|
||
} else {
|
||
if (EnablePlainTextPassword) {
|
||
if (pSession->pPassword != NULL) {
|
||
SmbPutUshort(
|
||
&pSessionSetupReq->PasswordLength,
|
||
pSession->pPassword->Length/2 + 1);
|
||
|
||
Status = SmbPutUnicodeStringAsOemString(
|
||
&pBuffer,
|
||
pSession->pPassword,
|
||
&BufferSize);
|
||
} else {
|
||
SmbPutUshort(&pSessionSetupReq->PasswordLength,1);
|
||
*pBuffer++ = '\0';
|
||
BufferSize -= sizeof(CHAR);
|
||
}
|
||
} else {
|
||
Status = STATUS_LOGON_FAILURE;
|
||
}
|
||
}
|
||
} else {
|
||
// Share level security. Send a null string for the password
|
||
SmbPutUshort(&pSessionSetupReq->PasswordLength,1);
|
||
*pBuffer++ = '\0';
|
||
BufferSize -= sizeof(CHAR);
|
||
}
|
||
}
|
||
|
||
// The User name and the domain name strings can be either copied from
|
||
// the information returned in the request response or the information
|
||
// that is already present in the session entry.
|
||
if (NT_SUCCESS(Status)) {
|
||
if ((pServer->Dialect == NTLANMAN_DIALECT) &&
|
||
(pServer->NtServer.NtCapabilities & CAP_UNICODE)) {
|
||
// Copy the account/domain names as UNICODE strings
|
||
PBYTE pTempBuffer = pBuffer;
|
||
|
||
RxDbgTrace( 0, Dbg, ("BuildSessionSetupSecurityInformation -- account/domain as unicode\n"));
|
||
pBuffer = ALIGN_SMB_WSTR(pBuffer);
|
||
BufferSize -= (ULONG)(pBuffer - pTempBuffer);
|
||
|
||
Status = SmbPutUnicodeString(
|
||
&pBuffer,
|
||
&UserName,
|
||
&BufferSize);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
Status = SmbPutUnicodeString(
|
||
&pBuffer,
|
||
&DomainName,
|
||
&BufferSize);
|
||
|
||
}
|
||
} else {
|
||
// Copy the account/domain names as ASCII strings.
|
||
RxDbgTrace( 0, Dbg, ("BuildSessionSetupSecurityInformation -- account/domain as ascii\n"));
|
||
Status = SmbPutUnicodeStringAsOemString(
|
||
&pBuffer,
|
||
&UserName,
|
||
&BufferSize);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
Status = SmbPutUnicodeStringAsOemString(
|
||
&pBuffer,
|
||
&DomainName,
|
||
&BufferSize);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
*pSmbBufferSize = BufferSize;
|
||
}
|
||
}
|
||
|
||
BuildNtLanmanResponseEpilogue(pExchange, &ResponseContext);
|
||
|
||
// Detach from the rdr process.
|
||
|
||
RxDbgTrace( -1, Dbg, ("BuildSessionSetupSecurityInformation -- Exit, status=%08lx\n",Status));
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
BuildTreeConnectSecurityInformation(
|
||
PSMB_EXCHANGE pExchange,
|
||
PBYTE pBuffer,
|
||
PBYTE pPasswordLength,
|
||
PULONG pSmbBufferSize)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine builds the security related information for the session setup SMB
|
||
|
||
Arguments:
|
||
|
||
pServer - the server instance
|
||
|
||
pLogonId - the logon id. for which the session is being setup
|
||
|
||
pPassword - the user supplied password if any
|
||
|
||
pBuffer - the password buffer
|
||
|
||
pPasswordLength - where the password length is to be stored
|
||
|
||
pSmbBufferSize - the size of the buffer on input ( modified to size remaining on
|
||
output)
|
||
|
||
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.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS FinalStatus,Status;
|
||
|
||
UNICODE_STRING UserName,DomainName;
|
||
STRING CaseSensitiveChallengeResponse,CaseInsensitiveChallengeResponse;
|
||
|
||
SECURITY_RESPONSE_CONTEXT ResponseContext;
|
||
|
||
ULONG PasswordLength = 0;
|
||
|
||
PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
|
||
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(pExchange);
|
||
|
||
PAGED_CODE();
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
if (pServer->EncryptPasswords) {
|
||
|
||
Status = BuildNtLanmanResponsePrologue(
|
||
pExchange,
|
||
&UserName,
|
||
&DomainName,
|
||
&CaseSensitiveChallengeResponse,
|
||
&CaseInsensitiveChallengeResponse,
|
||
&ResponseContext);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
if (FlagOn(pServer->DialectFlags,DF_MIXEDCASEPW)) {
|
||
RxDbgTrace( 0, Dbg, ("BuildTreeConnectSecurityInformation -- case sensitive password\n"));
|
||
// Copy the password length onto the SMB buffer
|
||
PasswordLength = CaseSensitiveChallengeResponse.Length;
|
||
|
||
// Copy the password
|
||
Status = SmbPutString(
|
||
&pBuffer,
|
||
&CaseSensitiveChallengeResponse,
|
||
pSmbBufferSize);
|
||
} else {
|
||
RxDbgTrace( 0, Dbg, ("BuildTreeConnectSecurityInformation -- case insensitive password\n"));
|
||
// Copy the password length onto the SMB buffer
|
||
PasswordLength = CaseInsensitiveChallengeResponse.Length;
|
||
|
||
// Copy the password
|
||
Status = SmbPutString(
|
||
&pBuffer,
|
||
&CaseInsensitiveChallengeResponse,
|
||
pSmbBufferSize);
|
||
}
|
||
|
||
BuildNtLanmanResponseEpilogue(pExchange, &ResponseContext);
|
||
}
|
||
|
||
} else {
|
||
if (pSession->pPassword == NULL) {
|
||
// The logon password cannot be sent as plain text. Send a Null string as password.
|
||
|
||
PasswordLength = 1;
|
||
if (*pSmbBufferSize >= 1) {
|
||
*((PCHAR)pBuffer) = '\0';
|
||
pBuffer += sizeof(CHAR);
|
||
Status = STATUS_SUCCESS;
|
||
} else {
|
||
Status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
} else {
|
||
if (EnablePlainTextPassword) {
|
||
OEM_STRING OemString;
|
||
|
||
OemString.Length = OemString.MaximumLength = (USHORT)(*pSmbBufferSize - sizeof(CHAR));
|
||
OemString.Buffer = pBuffer;
|
||
Status = RtlUnicodeStringToOemString(
|
||
&OemString,
|
||
pSession->pPassword,
|
||
FALSE);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
PasswordLength = OemString.Length+1;
|
||
}
|
||
} else {
|
||
Status = STATUS_LOGON_FAILURE;
|
||
}
|
||
}
|
||
|
||
// reduce the byte count
|
||
*pSmbBufferSize -= PasswordLength;
|
||
}
|
||
|
||
SmbPutUshort(pPasswordLength,(USHORT)PasswordLength);
|
||
|
||
return Status;
|
||
}
|
||
|