2025-04-27 07:49:33 -04:00

868 lines
30 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++ 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
--*/
#include "precomp.h"
#pragma hdrstop
#include "ntlsapi.h"
#define IsCredentialHandleValid(pCredHandle) \
(((pCredHandle)->dwLower != 0xffffffff) && ((pCredHandle)->dwUpper != 0xffffffff))
#define IsSecurityContextHandleValid(pContextHandle) \
(((pContextHandle)->dwLower != 0xffffffff) && ((pContextHandle)->dwUpper != 0xffffffff))
NTSTATUS
BuildSessionSetupSmb(
PSMB_EXCHANGE pExchange,
PGENERIC_ANDX pAndXSmb,
PULONG pAndXSmbBufferSize)
/*++
Routine Description:
This routine builds the session setup SMB for a NT server
Arguments:
pServer - the server instance
pSession - the SMBCE session instance
pAndXSmb - the session setup to be filled in
pAndXSmbBufferSize - the SMB buffer size on input modified to remaining size on
output.
Return Value:
RXSTATUS - 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;
PSMBCE_SERVER pServer = &pExchange->SmbCeContext.pServerEntry->Server;
PSMBCE_SESSION pSession = &pExchange->SmbCeContext.pSessionEntry->Session;
PREQ_SESSION_SETUP_ANDX pSessionSetup = (PREQ_SESSION_SETUP_ANDX)pAndXSmb;
PREQ_NT_SESSION_SETUP_ANDX pNtSessionSetup = (PREQ_NT_SESSION_SETUP_ANDX)pSessionSetup;
ULONG OriginalBufferSize = *pAndXSmbBufferSize;
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, 0);
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)){
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) &&
(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;
}
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
pLogonId - the logon id. for which the session is being setup
pPassword - the user supplied password if any
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;
BOOLEAN fProcessAttached = FALSE;
UNICODE_STRING UserName;
UNICODE_STRING DomainName;
STRING CaseSensitiveResponse;
STRING CaseInsensitiveResponse;
PSMBCE_SERVER pServer = &pExchange->SmbCeContext.pServerEntry->Server;
PSMBCE_SESSION pSession = &pExchange->SmbCeContext.pSessionEntry->Session;
SECURITY_RESPONSE_CONTEXT ResponseContext;
PAGED_CODE();
RxDbgTrace( +1, Dbg, ("BuildSessionSetupSecurityInformation -- Entry\n"));
// Attach to the redirector's FSP to allow us to call into the security impl.
if (PsGetCurrentProcess() != RxGetRDBSSProcess()) {
KeAttachProcess(RxGetRDBSSProcess());
fProcessAttached = TRUE;
}
Status = BuildNtLanmanResponsePrologue(
pExchange,
&UserName,
&DomainName,
&CaseSensitiveResponse,
&CaseInsensitiveResponse,
&ResponseContext);
if (NT_SUCCESS(Status)) {
PBYTE pBuffer = pSmbBuffer;
ULONG BufferSize = *pSmbBufferSize;
if (pServer->Dialect == NTLANMAN_DIALECT) {
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) {
// For othe lanman servers only the case sensitive password is required.
SmbPutUshort(&pSessionSetupReq->PasswordLength,
CaseInsensitiveResponse.Length);
// Copy the password
Status = SmbPutString(
&pBuffer,
&CaseInsensitiveResponse,
&BufferSize);
} 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 -= (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;
}
}
// Free the buffer allocated by the security package.
BuildNtLanmanResponseEpilogue(&ResponseContext);
// Detach from the rdr process.
if (fProcessAttached) {
KeDetachProcess();
}
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:
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 FinalStatus,Status;
BOOLEAN fProcessAttached = FALSE;
UNICODE_STRING UserName,DomainName;
STRING CaseSensitiveChallengeResponse,CaseInsensitiveChallengeResponse;
SECURITY_RESPONSE_CONTEXT ResponseContext;
ULONG PasswordLength = 0;
PSMBCE_SERVER pServer = &pExchange->SmbCeContext.pServerEntry->Server;
PSMBCE_SESSION pSession = &pExchange->SmbCeContext.pSessionEntry->Session;
PAGED_CODE();
Status = STATUS_SUCCESS;
if (pServer->EncryptPasswords) {
// Attach to the redirector's FSP to allow us to call into the securiy impl.
if (PsGetCurrentProcess() != RxGetRDBSSProcess()) {
KeAttachProcess(RxGetRDBSSProcess());
fProcessAttached = TRUE;
}
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(&ResponseContext);
}
if (fProcessAttached) {
KeDetachProcess();
}
} else {
if (pSession->pPassword == NULL) {
// The logon password cannot be sent as plain text. Send a single blank as password.
PasswordLength = 2;
if (*pSmbBufferSize >= 2) {
*((PCHAR)pBuffer) = ' ';
pBuffer += sizeof(CHAR);
*((PCHAR)pBuffer) = '\0';
pBuffer += sizeof(CHAR);
Status = STATUS_SUCCESS;
} else {
Status = STATUS_BUFFER_OVERFLOW;
}
} else {
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;
}
}
// reduce the byte count
*pSmbBufferSize -= PasswordLength;
}
SmbPutUshort(pPasswordLength,(USHORT)PasswordLength);
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
a NT server
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 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 AllocateSize;
PSMBCE_SERVER pServer = &pExchange->SmbCeContext.pServerEntry->Server;
PSMBCE_SESSION pSession = &pExchange->SmbCeContext.pSessionEntry->Session;
try {
pResponseContext->LanmanSetup.pOutputContextBuffer = 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;
}
// For Alignment purposes, we want InTokenSize rounded up to
// the nearest word size.
AllocateSize = ((InTokenSize + 3) & ~3) + NtlmInTokenSize;
ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
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);
ASSERT(IoGetCurrentProcess() == RxGetRDBSSProcess());
Status = ZwAllocateVirtualMemory(
NtCurrentProcess(),
&pOutputBufferDescriptor,
0L,
&OutputBufferDescriptorSize,
MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
pOutputBuffer = (SecBuffer *)(pOutputBufferDescriptor + 1);
pResponseContext->LanmanSetup.pOutputContextBuffer = 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) 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,
NULL,
&pSession->CredentialHandle,
&LifeTime);
if(!NT_SUCCESS(Status)) {
try_return(Status);
}
}
// Copy in the pass,user,domain if they were specified
if(pSession->pPassword != NULL) {
NtlmInToken->Password.Buffer = (PWSTR) p;
NtlmInToken->Password.Length = pSession->pPassword->Length;
NtlmInToken->Password.MaximumLength = pSession->pPassword->Length;
RtlCopyMemory(NtlmInToken->Password.Buffer,
pSession->pPassword->Buffer,
pSession->pPassword->Length);
NtlmInToken->Password.Buffer = (PWSTR) (p - (PUCHAR)NtlmInToken);
p += pSession->pPassword->Length;
}
if(pSession->pUserName != NULL) {
NtlmInToken->UserName.Buffer = (PWSTR) p;
NtlmInToken->UserName.Length = pSession->pUserName->Length;
NtlmInToken->UserName.MaximumLength = pSession->pUserName->Length;
RtlCopyMemory(NtlmInToken->UserName.Buffer,
pSession->pUserName->Buffer,
pSession->pUserName->Length);
NtlmInToken->UserName.Buffer = (PWSTR) (p - (PUCHAR)NtlmInToken);
p += pSession->pUserName->Length;
}
if (pSession->pUserDomainName != NULL) {
NtlmInToken->DomainName.Buffer = (PWSTR) p;
NtlmInToken->DomainName.Length = pSession->pUserDomainName->Length;
NtlmInToken->DomainName.MaximumLength = pSession->pUserDomainName->Length;
RtlCopyMemory(NtlmInToken->DomainName.Buffer,
pSession->pUserDomainName->Buffer,
pSession->pUserDomainName->Length);
NtlmInToken->DomainName.Buffer = (PWSTR) (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 = (PCHAR)InToken + sizeof(CHALLENGE_MESSAGE);
RtlCopyMemory(InToken->TargetName.Buffer,
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 != SEC_I_CONTINUE_NEEDED)) {
Status = MapSecurityError(Status);
DbgPrint("Initialize Security Context returned %lx\n",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)OutToken->NtChallengeResponse.Buffer;
}
if (ARGUMENT_PRESENT(pCaseInsensitiveResponse)) {
pCaseInsensitiveResponse->Length = OutToken->LmChallengeResponse.Length;
pCaseInsensitiveResponse->MaximumLength = OutToken->LmChallengeResponse.MaximumLength;
pCaseInsensitiveResponse->Buffer = (PBYTE)OutToken + (ULONG)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)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)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(pResponseContext);
}
}
return Status;
}
NTSTATUS
BuildNtLanmanResponseEpilogue(
PSECURITY_RESPONSE_CONTEXT pResponseContext)
{
if (pResponseContext->LanmanSetup.pOutputContextBuffer != NULL) {
ULONG i = 0;
SecBufferDesc *pBufferDescriptor = (SecBufferDesc *)pResponseContext->LanmanSetup.pOutputContextBuffer;
SecBuffer *pBuffer = pBufferDescriptor->pBuffers;
for (i = 0; i < pBufferDescriptor->cBuffers; i++) {
if (pBuffer[i].pvBuffer != NULL) {
FreeContextBuffer(pBuffer[i].pvBuffer);
}
}
}
pResponseContext->LanmanSetup.pOutputContextBuffer = NULL;
return STATUS_SUCCESS;
}
VOID
UninitializeSecurityContextsForSession(PSMBCE_SESSION pSession)
{
BOOLEAN fProcessAttached = FALSE;
if (IsCredentialHandleValid(&pSession->CredentialHandle)) {
FreeCredentialsHandle(&pSession->CredentialHandle);
}
if (IsSecurityContextHandleValid(&pSession->SecurityContextHandle)) {
if (PsGetCurrentProcess() != RxGetRDBSSProcess()) {
KeAttachProcess(RxGetRDBSSProcess());
fProcessAttached = TRUE;
}
DeleteSecurityContext(&pSession->SecurityContextHandle);
}
if (fProcessAttached) {
KeDetachProcess();
}
}