/*++ 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 #include #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 ) { if (*pAndXSmbBufferSize > 0) { pBuffer++; (*pAndXSmbBufferSize)--; } else { Status = STATUS_BUFFER_OVERFLOW; } } if (NT_SUCCESS(Status)) { 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((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((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; }