From 0784b176808873157c3083e0769759755a3adf6c Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Fri, 24 Apr 2020 12:52:53 -0700 Subject: [PATCH 01/26] Cached the protocol version on Managed SNI draft --- .../src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs | 5 +++++ .../Data/SqlClient/SNI/SNIMarsConnection.cs | 2 ++ .../Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs | 2 ++ .../Microsoft/Data/SqlClient/SNI/SNINpHandle.cs | 15 +++++++++++++++ .../Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs | 15 +++++++++++++++ .../src/Microsoft/Data/SqlClient/TdsParser.cs | 3 ++- .../Data/SqlClient/TdsParserStateObject.cs | 2 +- .../Data/SqlClient/TdsParserStateObjectManaged.cs | 7 ++++++- .../Data/SqlClient/TdsParserStateObjectNative.cs | 6 ++++-- 9 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs index 019ecf2b23..034097c21e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs @@ -87,6 +87,11 @@ internal abstract class SNIHandle public abstract Guid ConnectionId { get; } public virtual int ReserveHeaderSize => 0; + + /// + /// Gets a value that indicates the security protocol used to authenticate this connection. + /// + public virtual uint SChannelProtocol { get; } = 0; #if DEBUG /// /// Test handle for killing underlying connection diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs index f45b687cd7..cc5f58362a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs @@ -35,6 +35,8 @@ public Guid ConnectionId } } + public uint SChannelProtocol => (uint)_lowerHandle.SChannelProtocol; + /// /// Constructor /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs index 7c740be85c..35013f28b3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs @@ -46,6 +46,8 @@ internal sealed class SNIMarsHandle : SNIHandle public override int ReserveHeaderSize => SNISMUXHeader.HEADER_LENGTH; + public override uint SChannelProtocol => _connection.SChannelProtocol; + /// /// Dispose object /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 8b1d921a1f..787dd82b9c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -120,6 +120,21 @@ public override uint Status } } + public override uint SChannelProtocol + { + get + { + try + { + return (uint)_sslStream.SslProtocol; + } + catch + { + return base.SChannelProtocol; + } + } + } + public override uint CheckConnection() { long scopeID = SqlClientEventSource.Log.SNIScopeEnterEvent(""); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index ac4e819d1d..ce403076b3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -93,6 +93,21 @@ public override uint Status } } + public override uint SChannelProtocol + { + get + { + try + { + return (uint)_sslStream.SslProtocol; + } + catch + { + return base.SChannelProtocol; + } + } + } + /// /// Constructor /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 19f3398aac..a61cdfccbf 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -882,7 +882,8 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus info |= TdsEnums.SNI_SSL_IGNORE_CHANNEL_BINDINGS; } - error = _physicalStateObj.EnableSsl(ref info); + //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 + error = _physicalStateObj.EnableSsl(ref info, out uint protocol); if (error != TdsEnums.SNI_SUCCESS) { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 8e5d970bdb..850d6b7f37 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -772,7 +772,7 @@ private void ResetCancelAndProcessAttention() protected abstract void FreeGcHandle(int remaining, bool release); - internal abstract uint EnableSsl(ref uint info); + internal abstract uint EnableSsl(ref uint info, out uint sChannelProtocol); internal abstract uint WaitForSSLHandShakeToComplete(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs index 042cbb184f..1b302263cd 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs @@ -185,7 +185,12 @@ internal override uint EnableMars(ref uint info) return TdsEnums.SNI_ERROR; } - internal override uint EnableSsl(ref uint info) => SNIProxy.Singleton.EnableSsl(Handle, info); + internal override uint EnableSsl(ref uint info, out uint sChannelProtocol) + { + uint result = SNIProxy.Singleton.EnableSsl(Handle, info); + sChannelProtocol = Handle.SChannelProtocol; + return result; + } internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) => SNIProxy.Singleton.SetConnectionBufferSize(Handle, unsignedPacketSize); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index cbf2a78d83..278e5f6c4c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -297,10 +297,12 @@ internal override uint DisabeSsl() internal override uint EnableMars(ref uint info) => SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SMUX_PROV, ref info); - internal override uint EnableSsl(ref uint info) + internal override uint EnableSsl(ref uint info, out uint sChannelProtocol) { // Add SSL (Encryption) SNI provider. - return SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SSL_PROV, ref info); + uint result = SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SSL_PROV, ref info); + sChannelProtocol = 0; //TODO: Handle.SChannelProtocol; + return result; } internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) From 9266e65ffc4a4d323363149067e0a1d1b3d9846c Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Tue, 5 May 2020 14:18:59 -0700 Subject: [PATCH 02/26] Initial changes for SNI Merge testing --- .../src/Interop/SNINativeMethodWrapper.Windows.cs | 2 +- .../netcore/src/Microsoft.Data.SqlClient.csproj | 2 +- .../netfx/src/Microsoft.Data.SqlClient.csproj | 9 +++------ tools/props/Versions.props | 4 ++-- tools/specs/Microsoft.Data.SqlClient.nuspec | 8 ++++---- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index 6e34dbf975..53fe27c7bb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -245,7 +245,7 @@ internal struct SNI_Error [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] private static extern uint SNIOpenWrapper( [In] ref Sni_Consumer_Info pConsumerInfo, - [MarshalAs(UnmanagedType.LPStr)] string szConnect, + [MarshalAs(UnmanagedType.LPWStr)] string szConnect, [In] SNIHandle pConn, out IntPtr ppConn, [MarshalAs(UnmanagedType.Bool)] bool fSync); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index d1ddbf37af..95a1e7d07c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -665,7 +665,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 8a6ad37876..807847f171 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -82,19 +82,16 @@ - - - Microsoft\Data\SqlClient\SqlClientEventSource.cs - + Microsoft\Data\SqlClient\SqlClientLogger.cs - >Microsoft\Data\Common\ActivityCorrelator.cs + Microsoft\Data\Common\ActivityCorrelator.cs Microsoft\Data\Sql\SqlNotificationRequest.cs @@ -123,7 +120,7 @@ Microsoft\Data\SqlClient\ColumnEncryptionKeyInfo.cs - + Microsoft\Data\SqlClient\OnChangedEventHandler.cs diff --git a/tools/props/Versions.props b/tools/props/Versions.props index a56e0d4473..1db1bc6438 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -9,7 +9,7 @@ - 1.1.* + 2.0.0-dev 4.3.1 4.3.0 @@ -24,7 +24,7 @@ 4.7.0 - 4.4.0 + 2.0.0-dev 4.7.0 4.7.0 4.7.0 diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index a5079f9f52..824241e709 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -27,13 +27,13 @@ When using NuGet 3.x this package requires at least version 3.4. sqlclient microsoft.data.sqlclient - + - + @@ -45,7 +45,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -57,7 +57,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + From afa30320ebaa699d505cf9e7a64a2b5c7ff7661d Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Fri, 8 May 2020 16:39:53 -0700 Subject: [PATCH 03/26] Add testing support for .NET Standard/Package reference --- RunTests.cmd | 190 ++++++++++++++++-- build.proj | 67 +++--- src/Directory.Build.props | 28 ++- src/Microsoft.Data.SqlClient.sln | 52 ++++- ...waysEncrypted.AzureKeyVaultProvider.csproj | 9 +- .../add-ons/Directory.Build.props | 5 + .../netfx/ref/Microsoft.Data.SqlClient.csproj | 2 +- .../tests/Directory.Build.props | 1 + ...soft.Data.SqlClient.DockerLinuxTest.csproj | 2 +- .../Microsoft.Data.SqlClient.Tests.csproj | 23 ++- .../TestFixtures/Setup/CertificateUtility.cs | 8 +- ....Data.SqlClient.ManualTesting.Tests.csproj | 29 ++- .../SQL/UdtTest/UDTs/Address/Address.csproj | 6 +- .../SQL/UdtTest/UDTs/Circle/Circle.csproj | 6 +- .../SQL/UdtTest/UDTs/Shapes/Shapes.csproj | 6 +- .../UdtTest/UDTs/Utf8String/Utf8String.csproj | 6 +- .../Microsoft.Data.SqlClient.NSLibrary.csproj | 13 ++ tools/props/Versions.props | 4 + tools/specs/Microsoft.Data.SqlClient.nuspec | 98 ++++----- ...waysEncrypted.AzureKeyVaultProvider.nuspec | 24 +-- tools/testsql/createNorthwindDb.sql | 2 - 21 files changed, 421 insertions(+), 160 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj diff --git a/RunTests.cmd b/RunTests.cmd index 5e7cbfa1b9..9f20af9bd0 100644 --- a/RunTests.cmd +++ b/RunTests.cmd @@ -1,29 +1,177 @@ @echo off -call :pauseOnError msbuild /p:Configuration="Release" /t:Clean,BuildAllConfigurations -echo Building Add-Ons + +:: .NET CORE + .NET STANDARD LIBRARY TEST CASES +echo Building .NET Core Tests +call :pauseOnError msbuild /t:Clean + +:: ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" AND "NETSTANDARDPACKAGE" REFERENCE TYPES *************** +:: CREATE A NUGET PACKAGE WITH BELOW COMMAND AND ADD TO LOCAL FOLDER + UPDATE NUGET CONFIG FILE TO READ FROM THAT LOCATION +:: msbuild /p:configuration=Release + +:: REFERENCE TYPE "PACKAGE" +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildAKVNetFx /p:ReferenceType=Package +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildAKVNetCore /p:ReferenceType=Package + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=Package +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore2.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore2.1-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=Package /p:TargetNetCoreVersion=netcoreapp3.1 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=Package /p:TargetNetCoreVersion=netcoreapp5.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=Package /p:Platform=x64 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore2.1-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore2.1-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=Package /p:Platform=x64 /p:TargetNetCoreVersion=netcoreapp3.1 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=Package /p:Platform=x64 /p:TargetNetCoreVersion=netcoreapp5.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=Package /p:Platform=Win32 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore2.1-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore2.1-manual-win32.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=Package /p:Platform=Win32 /p:TargetNetCoreVersion=netcoreapp3.1 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-manual-win32.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=Package /p:Platform=Win32 /p:TargetNetCoreVersion=netcoreapp5.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-manual-win32.xml + +:: REFERENCE TYPE "NETSTANDARDPACKAGE" +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandardPackage +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore2.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore2.1-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandardPackage /p:TargetNetCoreVersion=netcoreapp3.1 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandardPackage /p:TargetNetCoreVersion=netcoreapp5.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:ReferenceType=NetStandardPackage /p:TargetNetFxVersion=net461 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetFxVersion=net461 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net461-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetFxVersion=net461 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net461-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:ReferenceType=NetStandardPackage /p:TargetNetFxVersion=net48 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetFxVersion=net48 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetFxVersion=net48 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandardPackage /p:Platform=x64 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore2.1-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore2.1-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandardPackage /p:Platform=x64 /p:TargetNetCoreVersion=netcoreapp3.1 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandardPackage /p:Platform=x64 /p:TargetNetCoreVersion=netcoreapp5.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:ReferenceType=NetStandardPackage /p:Platform=x64 /p:TargetNetFxVersion=net461 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetFxVersion=net461 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net461-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetFxVersion=net461 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net461-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:ReferenceType=NetStandardPackage /p:Platform=x64 /p:TargetNetFxVersion=net48 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetFxVersion=net48 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="x64" /p:TargetNetFxVersion=net48 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandardPackage /p:Platform=Win32 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore2.1-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore2.1-manual-win32.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandardPackage /p:Platform=Win32 /p:TargetNetCoreVersion=netcoreapp3.1 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-manual-win32.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandardPackage /p:Platform=Win32 /p:TargetNetCoreVersion=netcoreapp5.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-manual-win32.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:ReferenceType=NetStandardPackage /p:Platform=Win32 /p:TargetNetFxVersion=net461 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetFxVersion=net461 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net461-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetFxVersion=net461 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net461-manual-win32.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:ReferenceType=NetStandardPackage /p:Platform=Win32 /p:TargetNetFxVersion=net48 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetFxVersion=net48 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" /p:Platform="Win32" /p:TargetNetFxVersion=net48 /p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-manual-win32.xml + +:: REFERENCE TYPE "NETSTANDARD" (We only build and test AnyCPU with Project Reference) +:: NUGET PACKAGE GENERATION IS NOT SUPPORTED FOR REFERNCE TYPE 'NETSTANDARD' +call :pauseOnError msbuild /p:Configuration="Release" /p:ReferenceType=NetStandard /p:GenerateNuget=false +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandard +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore2.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore2.1-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandard /p:TargetNetCoreVersion=netcoreapp3.1 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore3.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore3.1-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:ReferenceType=NetStandard /p:TargetNetCoreVersion=netcoreapp5.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore5.0-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore5.0-manual-anycpu.xml + +:: TESTING 'NETSTANDARD' REFERENCE TYPE WITH .NET FRAMEWORK 4.6.1+ AS TARGET FRAMEWORK IS INVALID CASE AS PROJECT REFERENCE DOES NOT LOAD SNI.DLL IN .NET FRAMEWORK RUNTIME. +:: CASE IS VERIFIED WITH RUNTIME.NATIVE.SYSTEM.DATA.SQLCLIENT.SNI AS WELL. TO TEST .NET FRAMEWORK TARGETS, USE 'NETSTANDARDPACKAGE' REFERENCE TYPE ONLY. + +:: REFERENCE TYPE "PROJECT" (We only build and test AnyCPU with Project Reference) +call :pauseOnError msbuild /p:Configuration="Release" call :pauseOnError msbuild /p:Configuration="Release" /t:BuildAKVNetFx call :pauseOnError msbuild /p:Configuration="Release" /t:BuildAKVNetCoreAllOS -call :pauseOnError msbuild /p:configuration="Release" /t:GenerateAKVProviderNugetPackage -echo Building tests (Net46 + NetCoreApp2.1) +call :pauseOnError msbuild /p:Configuration="Release" /t:GenerateAKVProviderNugetPackage +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore2.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp2.1 /p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore2.1-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:TargetNetCoreVersion=netcoreapp3.1 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore3.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp3.1 /p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore3.1-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:TargetNetCoreVersion=netcoreapp5.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore5.0-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" /p:Platform="AnyCPU" /p:TargetNetCoreVersion=netcoreapp5.0 /p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore5.0-manual-anycpu.xml + + +:: .NET FRAMEWORK LIBRARY TEST CASES +echo Building .NET Framework Tests + call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx -call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore -echo Running SqlClient test suite (Net46 + NetCoreApp2.1) -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="Win32" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="x64" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="Win32" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="x64" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -echo Building tests (Net48 + NetCoreApp3.1) +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net46-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-ney46-manual-anycpu.xml + call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:TargetNetFxVersion=net48 -call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetCore /p:TargetNetCoreVersion=netcoreapp3.1 -echo Running SqlClient test suite (Net48 + NetCoreApp3.1) -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" /p:TargetNetCoreVersion=netcoreapp3.1 --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="Win32" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" /p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="x64" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" /p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetcoreapp" /p:TargetNetCoreVersion=netcoreapp3.1 --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="Win32" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" /p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="x64" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" /p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net48-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net48-manual-anycpu.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:Platform=x64 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="x64" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net46-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="x64" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net46-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:Platform=x64 /p:TargetNetFxVersion=net48 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="x64" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" /p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net48-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="x64" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" /p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net48-manual-x64.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:Platform=Win32 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="Win32" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net46-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="Win32" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net46-manual-win32.xml + +call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:Platform=Win32 /p:TargetNetFxVersion=net48 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="Win32" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" /p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net48-functional-Win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="Win32" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" /p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net48-manual-Win32.xml + goto :eof diff --git a/build.proj b/build.proj index 526a3fda65..c5c624489f 100644 --- a/build.proj +++ b/build.proj @@ -1,6 +1,5 @@ - - + + @@ -22,18 +21,20 @@ - - - + + + + - + + @@ -47,23 +48,29 @@ - - + + + + + + + + - + @@ -76,45 +83,51 @@ - - + + + + - - + + + + - - + - + + - + - + - + + + - - + + - - - + + + - - + + \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props index f20e408967..4a47928fd9 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -9,6 +9,19 @@ true true true + + Project $(DefineConstants);DEBUG @@ -16,27 +29,24 @@ $(MSBuildThisFileDirectory) $(ProjectDir)..\ + $(RepoRoot)artifacts\$(ReferenceType)\ $(ProjectDir)Microsoft.Data.SqlClient\ $(ManagedSourceCode)netcore\ $(ManagedSourceCode)netfx\ $(ManagedSourceCode)netfx\src\Resources\ - $(RepoRoot)obj\ + $(ManagedSourceCode)add-ons\ + $(Artifacts)obj\ $(NetCoreSource)src\Common\src $(NetCoreSource)src\Common\tests $(ProjectDir)Microsoft.Data.SqlClient\tests\ - $(RepoRoot)bin\Windows_NT\ - $(RepoRoot)bin\AnyOS\ - $(RepoRoot)bin\Unix\ + $(Artifacts)bin\Windows_NT\ + $(Artifacts)bin\AnyOS\ + $(Artifacts)bin\Unix\ $(RepoRoot)tools\ $(RepoRoot)packages\ $(RepoRoot).nuget\ $(NuGetRoot)nuget.exe - $(DOTNET_INSTALL_DIR) - $(RepoRoot).dotnet\ - $(DotNetRoot)\ - $(DotNetRoot)dotnet - $(DotNetCmd).exe true false diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index 63597ed179..9077063825 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29521.150 @@ -171,6 +170,8 @@ Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-co EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient.DockerLinuxTest", "Microsoft.Data.SqlClient\tests\DockerLinuxTest\Microsoft.Data.SqlClient.DockerLinuxTest.csproj", "{833157E1-1E53-4908-B4CB-5C5507A44582}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient.NSLibrary", "Microsoft.Data.SqlClient\tests\NSLibrary\Microsoft.Data.SqlClient.NSLibrary.csproj", "{E7336BFB-8521-423A-A140-3123F9065C5D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1035,6 +1036,54 @@ Global {833157E1-1E53-4908-B4CB-5C5507A44582}.Release|x64.Build.0 = Release|Any CPU {833157E1-1E53-4908-B4CB-5C5507A44582}.Release|x86.ActiveCfg = Release|Any CPU {833157E1-1E53-4908-B4CB-5C5507A44582}.Release|x86.Build.0 = Release|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|x64.ActiveCfg = Debug|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|x64.Build.0 = Debug|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|x86.ActiveCfg = Debug|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|x86.Build.0 = Debug|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Debug|Any CPU.Build.0 = Debug|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Debug|x64.ActiveCfg = Debug|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Debug|x64.Build.0 = Debug|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Debug|x86.ActiveCfg = Debug|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Debug|x86.Build.0 = Debug|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Release|Any CPU.ActiveCfg = Release|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Release|Any CPU.Build.0 = Release|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Release|x64.ActiveCfg = Release|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Release|x64.Build.0 = Release|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Release|x86.ActiveCfg = Release|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.net46-Release|x86.Build.0 = Release|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Debug|Any CPU.Build.0 = Debug|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Debug|x64.ActiveCfg = Debug|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Debug|x64.Build.0 = Debug|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Debug|x86.ActiveCfg = Debug|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Debug|x86.Build.0 = Debug|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Release|Any CPU.ActiveCfg = Release|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Release|Any CPU.Build.0 = Release|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Release|x64.ActiveCfg = Release|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Release|x64.Build.0 = Release|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Release|x86.ActiveCfg = Release|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp2.1-Release|x86.Build.0 = Release|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Debug|Any CPU.Build.0 = Debug|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Debug|x64.ActiveCfg = Debug|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Debug|x64.Build.0 = Debug|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Debug|x86.ActiveCfg = Debug|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Debug|x86.Build.0 = Debug|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Release|Any CPU.ActiveCfg = Release|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Release|Any CPU.Build.0 = Release|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Release|x64.ActiveCfg = Release|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Release|x64.Build.0 = Release|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Release|x86.ActiveCfg = Release|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.netcoreapp3.1-Release|x86.Build.0 = Release|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|Any CPU.Build.0 = Release|Any CPU + {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|x64.ActiveCfg = Release|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|x64.Build.0 = Release|x64 + {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|x86.ActiveCfg = Release|x86 + {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1066,6 +1115,7 @@ Global {650EB7FA-EB0D-4F8E-AB2C-161C3AD8E363} = {71F356DC-DFA3-4163-8BFE-D268722CE189} {5A7600BD-AED8-44AB-8F2A-7CB33A8D9C02} = {71F356DC-DFA3-4163-8BFE-D268722CE189} {833157E1-1E53-4908-B4CB-5C5507A44582} = {0CC4817A-12F3-4357-912C-09315FAAD008} + {E7336BFB-8521-423A-A140-3123F9065C5D} = {0CC4817A-12F3-4357-912C-09315FAAD008} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431} diff --git a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj index 9647acbf7f..b07eaa27bd 100644 --- a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj +++ b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj @@ -4,8 +4,8 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider AzureKeyVaultProvider {9073ABEF-92E0-4702-BB23-2C99CEF9BDD7} - netcoreapp - netfx + netcoreapp + netfx Debug;Release;net46-Release;net46-Debug;netcoreapp2.1-Debug;netcoreapp2.1-Release; AnyCPU;x86;x64 $(ObjFolder)$(Configuration).$(Platform)\$(AddOnName) @@ -17,8 +17,9 @@ true - - + + + diff --git a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props index 7469e3d558..4fc891665f 100644 --- a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props +++ b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props @@ -3,6 +3,11 @@ + + + Project + + diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj index 1425d80c32..4d5f63e325 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj @@ -1,7 +1,7 @@  false - net46 + net46 $(ObjFolder)$(Configuration)\$(AssemblyName)\ref\ $(BinFolder)$(Configuration)\$(AssemblyName)\ref\ $(OutputPath)\Microsoft.Data.SqlClient.xml diff --git a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props index 30fa92fe03..5d26340cf8 100644 --- a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props +++ b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props @@ -8,6 +8,7 @@ net46 netcoreapp2.1 + Project diff --git a/src/Microsoft.Data.SqlClient/tests/DockerLinuxTest/Microsoft.Data.SqlClient.DockerLinuxTest.csproj b/src/Microsoft.Data.SqlClient/tests/DockerLinuxTest/Microsoft.Data.SqlClient.DockerLinuxTest.csproj index 7d3ecb246c..1a452df62f 100644 --- a/src/Microsoft.Data.SqlClient/tests/DockerLinuxTest/Microsoft.Data.SqlClient.DockerLinuxTest.csproj +++ b/src/Microsoft.Data.SqlClient/tests/DockerLinuxTest/Microsoft.Data.SqlClient.DockerLinuxTest.csproj @@ -10,6 +10,6 @@ - + diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 94cb627d09..8eb7423421 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -1,14 +1,15 @@  false + FunctionalTests netcoreapp netfx Debug;Release;net46-Release;net46-Debug;netcoreapp2.1-Debug;netcoreapp2.1-Release;netcoreapp3.1-Debug;netcoreapp3.1-Release AnyCPU;x86;x64 - $(ObjFolder)$(Configuration).FunctionalTests - $(BinFolder)$(Configuration).FunctionalTests + $(ObjFolder)$(Configuration).$(Platform).$(AssemblyName) + $(BinFolder)$(Configuration).$(Platform).$(AssemblyName) - + @@ -21,6 +22,8 @@ + + @@ -51,7 +54,7 @@ - + @@ -59,7 +62,7 @@ - + @@ -81,10 +84,14 @@ Microsoft.DotNet.XUnitExtensions - - + + + + + + - + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtility.cs index 68d0c25f68..6a66bf487e 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtility.cs @@ -271,7 +271,7 @@ internal static SqlConnection GetOpenConnection(bool fTceEnabled, SqlConnectionS conn.Dispose(); throw; } - + SqlConnection.ClearPool(conn); return conn; } @@ -281,11 +281,7 @@ internal static SqlConnection GetOpenConnection(bool fTceEnabled, SqlConnectionS /// public static string GetConnectionString(bool fTceEnabled, SqlConnectionStringBuilder sb, bool fSuppressAttestation = false) { - SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); - builder.DataSource = sb.DataSource; - builder.InitialCatalog = sb.InitialCatalog; - builder.UserID = sb.UserID; - builder.Password = sb.Password; + SqlConnectionStringBuilder builder = sb; if (fTceEnabled) { builder.ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 7db44f4358..b6236d865c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -1,6 +1,7 @@  {45DB5F86-7AE3-45C6-870D-F9357B66BDB5} + ManualTests netcoreapp netfx false @@ -9,16 +10,13 @@ AnyCPU;x86;x64 $(DefineConstants);netcoreapp $(DefineConstants);netfx - $(ObjFolder)$(Configuration).ManualTests - $(BinFolder)$(Configuration).ManualTests + $(ObjFolder)$(Configuration).$(Platform).$(AssemblyName) + $(BinFolder)$(Configuration).$(Platform).$(AssemblyName) - - - Common\System\Collections\DictionaryExtensions.cs - + @@ -57,6 +55,11 @@ + + + + Common\System\Collections\DictionaryExtensions.cs + @@ -236,7 +239,7 @@ - + @@ -244,7 +247,6 @@ - Microsoft.DotNet.XUnitExtensions @@ -266,11 +268,16 @@ CoreFx.Private.TestUtilities - - + + + + + + + @@ -280,6 +287,6 @@ - + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj index 511a9c0702..b83e9debb0 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj @@ -11,7 +11,9 @@ $(BinFolder)$(Configuration).$(Platform)\$(AssemblyName) - - + + + + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Circle/Circle.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Circle/Circle.csproj index a0d0585b13..e6e19d1655 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Circle/Circle.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Circle/Circle.csproj @@ -11,7 +11,9 @@ $(BinFolder)$(Configuration).$(Platform)\$(AssemblyName) - - + + + + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Shapes/Shapes.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Shapes/Shapes.csproj index bba3565c0e..91bfcd395f 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Shapes/Shapes.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Shapes/Shapes.csproj @@ -11,7 +11,9 @@ $(BinFolder)$(Configuration).$(Platform)\$(AssemblyName) - - + + + + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Utf8String/Utf8String.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Utf8String/Utf8String.csproj index 2415e28685..5826c8f99e 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Utf8String/Utf8String.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Utf8String/Utf8String.csproj @@ -11,7 +11,9 @@ $(BinFolder)$(Configuration).$(Platform)\$(AssemblyName) - - + + + + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj b/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj new file mode 100644 index 0000000000..5c1d2ce4c5 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.0 + AnyCPU;x86;x64 + $(ObjFolder)$(Configuration).$(Platform)\$(AssemblyName) + $(BinFolder)$(Configuration).$(Platform)\$(AssemblyName) + + + + + + diff --git a/tools/props/Versions.props b/tools/props/Versions.props index 1db1bc6438..f719fa55d3 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -61,4 +61,8 @@ 5.0.0-beta.20206.4 2.0.8 + + $(NugetPackageVersion) + $(NugetPackageVersion) + diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 824241e709..0d9788c5bb 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -27,7 +27,7 @@ When using NuGet 3.x this package requires at least version 3.4. sqlclient microsoft.data.sqlclient - + @@ -99,75 +99,75 @@ When using NuGet 3.x this package requires at least version 3.4. - - - + + + - - - + + + - - - + + + - - - + + + - - - - - - - - - - + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - - - + + + + - - - - + + + + - - - - + + + + diff --git a/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec b/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec index fcf2afcccd..62365bd9da 100644 --- a/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec +++ b/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec @@ -48,21 +48,21 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyStoreProvider.SqlColumnEncrypti - - - - - + + + + + - - - + + + - - - + + + - + diff --git a/tools/testsql/createNorthwindDb.sql b/tools/testsql/createNorthwindDb.sql index fd12f1821e..01f48aaec6 100644 --- a/tools/testsql/createNorthwindDb.sql +++ b/tools/testsql/createNorthwindDb.sql @@ -18,8 +18,6 @@ END CREATE DATABASE [Northwind] GO -ALTER DATABASE [Northwind] SET COMPATIBILITY_LEVEL = 100 -GO ALTER DATABASE [Northwind] SET ANSI_NULL_DEFAULT OFF GO ALTER DATABASE [Northwind] SET ANSI_NULLS OFF From b4cbbeff8de9555780f43b4428dfba5b296f4582 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Mon, 11 May 2020 17:01:53 -0700 Subject: [PATCH 04/26] More improvements + renamed SNI.dll --- src/Directory.Build.props | 2 +- ....SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj | 2 +- .../netcore/src/Interop/SNINativeMethodWrapper.Windows.cs | 2 +- .../src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs | 2 +- .../FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj | 3 +-- .../Microsoft.Data.SqlClient.ManualTesting.Tests.csproj | 7 +++---- src/NuGet.config | 3 ++- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 4a47928fd9..c56d604473 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -13,7 +13,7 @@ "ReferenceType" property supports below options: "Project" => Build and run tests with Microsoft.Data.SqlClient as Project Reference - "Package" => Build and run tests with Microsoft.Data.SqlClient as Package Reference with configured "MicrosoftDataSqlClientVersion" in "Versions.props" file. + "Package" => Build and run tests with Microsoft.Data.SqlClient as Package Reference with configured "TestMicrosoftDataSqlClientVersion" in "Versions.props" file. "NetStandard" => Build and run tests with Microsoft.Data.SqlClient as Project Reference via .NET Standard Library "NetStandardPackage" => Build and run tests with Microsoft.Data.SqlClient as Package Reference via .NET Standard Library diff --git a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj index b07eaa27bd..9a32df9809 100644 --- a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj +++ b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index 53fe27c7bb..1296e4afa3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -11,7 +11,7 @@ namespace Microsoft.Data.SqlClient { internal static partial class SNINativeMethodWrapper { - private const string SNI = "sni.dll"; + private const string SNI = "Microsoft.Data.SqlClient.SNI.dll"; private static int s_sniMaxComposedSpnLength = -1; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index 5a724ec716..90a539b1e7 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -18,7 +18,7 @@ namespace Microsoft.Data.SqlClient { internal static class SNINativeMethodWrapper { - private const string SNI = "SNI.dll"; + private const string SNI = "Microsoft.Data.SqlClient.SNI.dll"; private static int s_sniMaxComposedSpnLength = -1; diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 8eb7423421..bf0cc6b35f 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -86,10 +86,9 @@ - + - diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index b6236d865c..cc5e0b5d80 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -270,20 +270,19 @@ - + - - + - + diff --git a/src/NuGet.config b/src/NuGet.config index cb7e89cd4a..0c7721a7d7 100644 --- a/src/NuGet.config +++ b/src/NuGet.config @@ -1,9 +1,10 @@ - + + From b895c1497134385774951987fdf27c5a1d7b23a7 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Mon, 11 May 2020 17:29:08 -0700 Subject: [PATCH 05/26] Receive protocol version draft --- .../src/Interop/SNINativeMethodWrapper.Windows.cs | 2 +- .../src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs | 2 +- .../Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs | 2 +- .../src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs | 2 +- .../src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs | 4 ++-- .../src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs | 4 ++-- .../src/Microsoft/Data/SqlClient/TdsParser.Windows.cs | 5 +++-- .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 7 ++++--- .../src/Microsoft/Data/SqlClient/TdsParserStateObject.cs | 4 ++-- .../Data/SqlClient/TdsParserStateObjectManaged.cs | 9 ++++++--- .../Data/SqlClient/TdsParserStateObjectNative.cs | 7 +++---- 11 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index 6e34dbf975..a0e49ab3aa 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -225,7 +225,7 @@ internal struct SNI_Error internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs index 034097c21e..1f9caa8afb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs @@ -91,7 +91,7 @@ internal abstract class SNIHandle /// /// Gets a value that indicates the security protocol used to authenticate this connection. /// - public virtual uint SChannelProtocol { get; } = 0; + public virtual uint ProtocolVersion { get; } = 0; #if DEBUG /// /// Test handle for killing underlying connection diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs index cc5f58362a..2790688c30 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs @@ -35,7 +35,7 @@ public Guid ConnectionId } } - public uint SChannelProtocol => (uint)_lowerHandle.SChannelProtocol; + public uint ProtocolVersion => (uint)_lowerHandle.ProtocolVersion; /// /// Constructor diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs index 35013f28b3..3089c08112 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs @@ -46,7 +46,7 @@ internal sealed class SNIMarsHandle : SNIHandle public override int ReserveHeaderSize => SNISMUXHeader.HEADER_LENGTH; - public override uint SChannelProtocol => _connection.SChannelProtocol; + public override uint ProtocolVersion => _connection.ProtocolVersion; /// /// Dispose object diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 787dd82b9c..c0ead621f0 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -120,7 +120,7 @@ public override uint Status } } - public override uint SChannelProtocol + public override uint ProtocolVersion { get { @@ -130,7 +130,7 @@ public override uint SChannelProtocol } catch { - return base.SChannelProtocol; + return base.ProtocolVersion; } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index ce403076b3..2e9aa2e3a2 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -93,7 +93,7 @@ public override uint Status } } - public override uint SChannelProtocol + public override uint ProtocolVersion { get { @@ -103,7 +103,7 @@ public override uint SChannelProtocol } catch { - return base.SChannelProtocol; + return base.ProtocolVersion; } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs index 4e60f4e7f6..1903a8fcc6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs @@ -75,15 +75,16 @@ private void LoadSSPILibrary() } } - private void WaitForSSLHandShakeToComplete(ref uint error) + private void WaitForSSLHandShakeToComplete(ref uint error, out uint protocolVersion) { + protocolVersion = 0; if (TdsParserStateObjectFactory.UseManagedSNI) return; // in the case where an async connection is made, encryption is used and Windows Authentication is used, // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete // before calling SNISecGenClientContext). - error = _physicalStateObj.WaitForSSLHandShakeToComplete(); + error = _physicalStateObj.WaitForSSLHandShakeToComplete(out protocolVersion); if (error != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index a61cdfccbf..1b0b61658e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -882,8 +882,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus info |= TdsEnums.SNI_SSL_IGNORE_CHANNEL_BINDINGS; } - //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 - error = _physicalStateObj.EnableSsl(ref info, out uint protocol); + error = _physicalStateObj.EnableSsl(ref info); if (error != TdsEnums.SNI_SUCCESS) { @@ -891,7 +890,9 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus ThrowExceptionAndWarning(_physicalStateObj); } - WaitForSSLHandShakeToComplete(ref error); + //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 + WaitForSSLHandShakeToComplete(ref error, out uint protocolVersion); + Console.WriteLine(protocolVersion); // create a new packet encryption changes the internal packet size _physicalStateObj.ClearAllWritePackets(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 850d6b7f37..47dd5cb649 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -772,9 +772,9 @@ private void ResetCancelAndProcessAttention() protected abstract void FreeGcHandle(int remaining, bool release); - internal abstract uint EnableSsl(ref uint info, out uint sChannelProtocol); + internal abstract uint EnableSsl(ref uint info); - internal abstract uint WaitForSSLHandShakeToComplete(); + internal abstract uint WaitForSSLHandShakeToComplete(out uint protocolVersion); internal abstract void Dispose(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs index 1b302263cd..33f5df7740 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs @@ -185,10 +185,9 @@ internal override uint EnableMars(ref uint info) return TdsEnums.SNI_ERROR; } - internal override uint EnableSsl(ref uint info, out uint sChannelProtocol) + internal override uint EnableSsl(ref uint info) { uint result = SNIProxy.Singleton.EnableSsl(Handle, info); - sChannelProtocol = Handle.SChannelProtocol; return result; } @@ -205,6 +204,10 @@ internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint recei return 0; } - internal override uint WaitForSSLHandShakeToComplete() => 0; + internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) + { + protocolVersion = Handle.ProtocolVersion; + return 0; + } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index 278e5f6c4c..701a10c78c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -297,11 +297,10 @@ internal override uint DisabeSsl() internal override uint EnableMars(ref uint info) => SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SMUX_PROV, ref info); - internal override uint EnableSsl(ref uint info, out uint sChannelProtocol) + internal override uint EnableSsl(ref uint info) { // Add SSL (Encryption) SNI provider. uint result = SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SSL_PROV, ref info); - sChannelProtocol = 0; //TODO: Handle.SChannelProtocol; return result; } @@ -311,8 +310,8 @@ internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint receivedLength, ref byte[] sendBuff, ref uint sendLength, byte[] _sniSpnBuffer) => SNINativeMethodWrapper.SNISecGenClientContext(Handle, receivedBuff, receivedLength, sendBuff, ref sendLength, _sniSpnBuffer); - internal override uint WaitForSSLHandShakeToComplete() - => SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining()); + internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) + => SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining(), out protocolVersion); internal override void DisposePacketCache() { From 7f74273969502aee7ff84bf4c00eedc7787cf9f9 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Mon, 11 May 2020 17:29:08 -0700 Subject: [PATCH 06/26] Receive protocol version draft --- .../src/Interop/SNINativeMethodWrapper.Windows.cs | 2 +- .../src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs | 2 +- .../Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs | 2 +- .../src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs | 2 +- .../src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs | 4 ++-- .../src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs | 4 ++-- .../src/Microsoft/Data/SqlClient/TdsParser.Windows.cs | 5 +++-- .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 7 ++++--- .../src/Microsoft/Data/SqlClient/TdsParserStateObject.cs | 4 ++-- .../Data/SqlClient/TdsParserStateObjectManaged.cs | 9 ++++++--- .../Data/SqlClient/TdsParserStateObjectNative.cs | 7 +++---- .../src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs | 2 +- .../netfx/src/Microsoft/Data/SqlClient/TdsParser.cs | 4 +++- 13 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index 6e34dbf975..a0e49ab3aa 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -225,7 +225,7 @@ internal struct SNI_Error internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs index 034097c21e..1f9caa8afb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs @@ -91,7 +91,7 @@ internal abstract class SNIHandle /// /// Gets a value that indicates the security protocol used to authenticate this connection. /// - public virtual uint SChannelProtocol { get; } = 0; + public virtual uint ProtocolVersion { get; } = 0; #if DEBUG /// /// Test handle for killing underlying connection diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs index cc5f58362a..2790688c30 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs @@ -35,7 +35,7 @@ public Guid ConnectionId } } - public uint SChannelProtocol => (uint)_lowerHandle.SChannelProtocol; + public uint ProtocolVersion => (uint)_lowerHandle.ProtocolVersion; /// /// Constructor diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs index 35013f28b3..3089c08112 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs @@ -46,7 +46,7 @@ internal sealed class SNIMarsHandle : SNIHandle public override int ReserveHeaderSize => SNISMUXHeader.HEADER_LENGTH; - public override uint SChannelProtocol => _connection.SChannelProtocol; + public override uint ProtocolVersion => _connection.ProtocolVersion; /// /// Dispose object diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 787dd82b9c..c0ead621f0 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -120,7 +120,7 @@ public override uint Status } } - public override uint SChannelProtocol + public override uint ProtocolVersion { get { @@ -130,7 +130,7 @@ public override uint SChannelProtocol } catch { - return base.SChannelProtocol; + return base.ProtocolVersion; } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index ce403076b3..2e9aa2e3a2 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -93,7 +93,7 @@ public override uint Status } } - public override uint SChannelProtocol + public override uint ProtocolVersion { get { @@ -103,7 +103,7 @@ public override uint SChannelProtocol } catch { - return base.SChannelProtocol; + return base.ProtocolVersion; } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs index 4e60f4e7f6..1903a8fcc6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs @@ -75,15 +75,16 @@ private void LoadSSPILibrary() } } - private void WaitForSSLHandShakeToComplete(ref uint error) + private void WaitForSSLHandShakeToComplete(ref uint error, out uint protocolVersion) { + protocolVersion = 0; if (TdsParserStateObjectFactory.UseManagedSNI) return; // in the case where an async connection is made, encryption is used and Windows Authentication is used, // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete // before calling SNISecGenClientContext). - error = _physicalStateObj.WaitForSSLHandShakeToComplete(); + error = _physicalStateObj.WaitForSSLHandShakeToComplete(out protocolVersion); if (error != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index a61cdfccbf..1b0b61658e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -882,8 +882,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus info |= TdsEnums.SNI_SSL_IGNORE_CHANNEL_BINDINGS; } - //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 - error = _physicalStateObj.EnableSsl(ref info, out uint protocol); + error = _physicalStateObj.EnableSsl(ref info); if (error != TdsEnums.SNI_SUCCESS) { @@ -891,7 +890,9 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus ThrowExceptionAndWarning(_physicalStateObj); } - WaitForSSLHandShakeToComplete(ref error); + //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 + WaitForSSLHandShakeToComplete(ref error, out uint protocolVersion); + Console.WriteLine(protocolVersion); // create a new packet encryption changes the internal packet size _physicalStateObj.ClearAllWritePackets(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 850d6b7f37..47dd5cb649 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -772,9 +772,9 @@ private void ResetCancelAndProcessAttention() protected abstract void FreeGcHandle(int remaining, bool release); - internal abstract uint EnableSsl(ref uint info, out uint sChannelProtocol); + internal abstract uint EnableSsl(ref uint info); - internal abstract uint WaitForSSLHandShakeToComplete(); + internal abstract uint WaitForSSLHandShakeToComplete(out uint protocolVersion); internal abstract void Dispose(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs index 1b302263cd..33f5df7740 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs @@ -185,10 +185,9 @@ internal override uint EnableMars(ref uint info) return TdsEnums.SNI_ERROR; } - internal override uint EnableSsl(ref uint info, out uint sChannelProtocol) + internal override uint EnableSsl(ref uint info) { uint result = SNIProxy.Singleton.EnableSsl(Handle, info); - sChannelProtocol = Handle.SChannelProtocol; return result; } @@ -205,6 +204,10 @@ internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint recei return 0; } - internal override uint WaitForSSLHandShakeToComplete() => 0; + internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) + { + protocolVersion = Handle.ProtocolVersion; + return 0; + } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index 278e5f6c4c..701a10c78c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -297,11 +297,10 @@ internal override uint DisabeSsl() internal override uint EnableMars(ref uint info) => SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SMUX_PROV, ref info); - internal override uint EnableSsl(ref uint info, out uint sChannelProtocol) + internal override uint EnableSsl(ref uint info) { // Add SSL (Encryption) SNI provider. uint result = SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SSL_PROV, ref info); - sChannelProtocol = 0; //TODO: Handle.SChannelProtocol; return result; } @@ -311,8 +310,8 @@ internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint receivedLength, ref byte[] sendBuff, ref uint sendLength, byte[] _sniSpnBuffer) => SNINativeMethodWrapper.SNISecGenClientContext(Handle, receivedBuff, receivedLength, sendBuff, ref sendLength, _sniSpnBuffer); - internal override uint WaitForSSLHandShakeToComplete() - => SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining()); + internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) + => SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining(), out protocolVersion); internal override void DisposePacketCache() { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index f942f1c9c0..4033cce1a4 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -445,7 +445,7 @@ internal struct SNI_Error internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index eed44ac752..0ded0eebc5 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1189,7 +1189,9 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(SqlAuthenticationMethod // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete // before calling SNISecGenClientContext). - error = SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(_physicalStateObj.Handle, _physicalStateObj.GetTimeoutRemaining()); + error = SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(_physicalStateObj.Handle, _physicalStateObj.GetTimeoutRemaining(), out uint protocolVersion); + Console.WriteLine(protocolVersion); //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 + if (error != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); From c239acc31131bfe476f9efdc955bfa938c11e3b8 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Tue, 12 May 2020 12:33:10 -0700 Subject: [PATCH 07/26] EOF --- build.proj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.proj b/build.proj index c5c624489f..edebcec39e 100644 --- a/build.proj +++ b/build.proj @@ -130,4 +130,4 @@ - \ No newline at end of file + From 57a3c89be122d3315529bc6ea61671066584fb98 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Tue, 12 May 2020 14:05:16 -0700 Subject: [PATCH 08/26] Spell --- RunTests.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RunTests.cmd b/RunTests.cmd index 9f20af9bd0..b167d91e40 100644 --- a/RunTests.cmd +++ b/RunTests.cmd @@ -150,7 +150,7 @@ echo Building .NET Framework Tests call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net46-functional-anycpu.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-ney46-manual-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net46-manual-anycpu.xml call :pauseOnError msbuild /p:Configuration="Release" /t:BuildTestsNetFx /p:TargetNetFxVersion=net48 call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" /p:Platform="AnyCPU" /p:Configuration="Release" /p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-net48-functional-anycpu.xml From 6acc1b20b5e47473906115575ad0e51ad628e4d4 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 13 May 2020 10:24:41 -0700 Subject: [PATCH 09/26] Added project configurations --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 5 +- tools/specs/Microsoft.Data.SqlClient.nuspec | 74 ++++++++++++------- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 807847f171..66eff3cdea 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -417,7 +417,10 @@ $(SystemSecurityCryptographyPrimitivesVersion) - + + $(MicrosoftDataSqlClientSniVersion) + + $(MicrosoftDataSqlClientSniVersion) diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 0d9788c5bb..22be0d9a27 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -9,25 +9,45 @@ MIT https://aka.ms/sqlclientproject dotnet.png - Provides the data provider for SQL Server. These classes provide access to versions of SQL Server and encapsulate database-specific protocols, including tabular data stream (TDS) - -Commonly Used Types: -Microsoft.Data.SqlClient.SqlConnection -Microsoft.Data.SqlClient.SqlException -Microsoft.Data.SqlClient.SqlParameter -Microsoft.Data.SqlClient.SqlDataReader -Microsoft.Data.SqlClient.SqlCommand -Microsoft.Data.SqlClient.SqlTransaction -Microsoft.Data.SqlClient.SqlParameterCollection -Microsoft.Data.SqlClient.SqlClientFactory - -When using NuGet 3.x this package requires at least version 3.4. + + Provides the data provider for SQL Server. These classes provide access to versions of SQL Server and encapsulate database-specific protocols, including tabular data stream (TDS) + + Commonly Used Types: + Microsoft.Data.SqlClient.SqlConnection + Microsoft.Data.SqlClient.SqlException + Microsoft.Data.SqlClient.SqlParameter + Microsoft.Data.SqlClient.SqlDataReader + Microsoft.Data.SqlClient.SqlCommand + Microsoft.Data.SqlClient.SqlTransaction + Microsoft.Data.SqlClient.SqlParameterCollection + Microsoft.Data.SqlClient.SqlClientFactory + + When using NuGet 3.x this package requires at least version 3.4. + https://go.microsoft.com/fwlink/?linkid=2090501 © Microsoft Corporation. All rights reserved. sqlclient microsoft.data.sqlclient - - + + + + + + + + + + + + + + + + + + + + @@ -74,24 +94,24 @@ When using NuGet 3.x this package requires at least version 3.4. - - - + + + - - - + + + - - - + + + - - - + + + From ec0ffe263cf53268e817c248e1469f40c186b769 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 13 May 2020 11:24:01 -0700 Subject: [PATCH 10/26] Merged with Cheena 'temp-sni-merge' --- .../Interop/SNINativeMethodWrapper.Windows.cs | 2 +- .../Microsoft/Data/SqlClient/SNI/SNIHandle.cs | 5 ++ .../Data/SqlClient/SNI/SNIMarsConnection.cs | 2 + .../Data/SqlClient/SNI/SNIMarsHandle.cs | 2 + .../Data/SqlClient/SNI/SNINpHandle.cs | 15 ++++ .../Data/SqlClient/SNI/SNITcpHandle.cs | 15 ++++ .../Data/SqlClient/TdsParser.Windows.cs | 5 +- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 4 +- .../Data/SqlClient/TdsParserStateObject.cs | 2 +- .../SqlClient/TdsParserStateObjectManaged.cs | 12 ++- .../SqlClient/TdsParserStateObjectNative.cs | 7 +- .../netfx/src/Microsoft.Data.SqlClient.csproj | 5 +- .../Data/Interop/SNINativeMethodWrapper.cs | 2 +- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 4 +- tools/specs/Microsoft.Data.SqlClient.nuspec | 74 ++++++++++++------- 15 files changed, 116 insertions(+), 40 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index 1296e4afa3..9f64f00bec 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -225,7 +225,7 @@ internal struct SNI_Error internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs index 019ecf2b23..1f9caa8afb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs @@ -87,6 +87,11 @@ internal abstract class SNIHandle public abstract Guid ConnectionId { get; } public virtual int ReserveHeaderSize => 0; + + /// + /// Gets a value that indicates the security protocol used to authenticate this connection. + /// + public virtual uint ProtocolVersion { get; } = 0; #if DEBUG /// /// Test handle for killing underlying connection diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs index a78bdd1aa2..11f3544f7a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs @@ -35,6 +35,8 @@ public Guid ConnectionId } } + public uint ProtocolVersion => (uint)_lowerHandle.ProtocolVersion; + /// /// Constructor /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs index 7c740be85c..3089c08112 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs @@ -46,6 +46,8 @@ internal sealed class SNIMarsHandle : SNIHandle public override int ReserveHeaderSize => SNISMUXHeader.HEADER_LENGTH; + public override uint ProtocolVersion => _connection.ProtocolVersion; + /// /// Dispose object /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index d01b22631d..7bfc5cebf3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -120,6 +120,21 @@ public override uint Status } } + public override uint ProtocolVersion + { + get + { + try + { + return (uint)_sslStream.SslProtocol; + } + catch + { + return base.ProtocolVersion; + } + } + } + public override uint CheckConnection() { long scopeID = SqlClientEventSource.Log.SNIScopeEnterEvent(""); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index ac4e819d1d..2e9aa2e3a2 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -93,6 +93,21 @@ public override uint Status } } + public override uint ProtocolVersion + { + get + { + try + { + return (uint)_sslStream.SslProtocol; + } + catch + { + return base.ProtocolVersion; + } + } + } + /// /// Constructor /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs index 4e60f4e7f6..1903a8fcc6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs @@ -75,15 +75,16 @@ private void LoadSSPILibrary() } } - private void WaitForSSLHandShakeToComplete(ref uint error) + private void WaitForSSLHandShakeToComplete(ref uint error, out uint protocolVersion) { + protocolVersion = 0; if (TdsParserStateObjectFactory.UseManagedSNI) return; // in the case where an async connection is made, encryption is used and Windows Authentication is used, // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete // before calling SNISecGenClientContext). - error = _physicalStateObj.WaitForSSLHandShakeToComplete(); + error = _physicalStateObj.WaitForSSLHandShakeToComplete(out protocolVersion); if (error != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index cfac61e4c7..c94e43398e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -900,7 +900,9 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus ThrowExceptionAndWarning(_physicalStateObj); } - WaitForSSLHandShakeToComplete(ref error); + //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 + WaitForSSLHandShakeToComplete(ref error, out uint protocolVersion); + Console.WriteLine(protocolVersion); // create a new packet encryption changes the internal packet size _physicalStateObj.ClearAllWritePackets(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 915a28d664..bfe1a5bf78 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -774,7 +774,7 @@ private void ResetCancelAndProcessAttention() internal abstract uint EnableSsl(ref uint info); - internal abstract uint WaitForSSLHandShakeToComplete(); + internal abstract uint WaitForSSLHandShakeToComplete(out uint protocolVersion); internal abstract void Dispose(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs index 3efac3d278..88f60bf700 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs @@ -185,7 +185,11 @@ internal override uint EnableMars(ref uint info) return TdsEnums.SNI_ERROR; } - internal override uint EnableSsl(ref uint info) => SNIProxy.Singleton.EnableSsl(Handle, info); + internal override uint EnableSsl(ref uint info) + { + uint result = SNIProxy.Singleton.EnableSsl(Handle, info); + return result; + } internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) => SNIProxy.Singleton.SetConnectionBufferSize(Handle, unsignedPacketSize); @@ -200,6 +204,10 @@ internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint recei return 0; } - internal override uint WaitForSSLHandShakeToComplete() => 0; + internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) + { + protocolVersion = Handle.ProtocolVersion; + return 0; + } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index 97825278ec..aa2d532c65 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -300,7 +300,8 @@ internal override uint EnableMars(ref uint info) internal override uint EnableSsl(ref uint info) { // Add SSL (Encryption) SNI provider. - return SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SSL_PROV, ref info); + uint result = SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SSL_PROV, ref info); + return result; } internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) @@ -309,8 +310,8 @@ internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint receivedLength, ref byte[] sendBuff, ref uint sendLength, byte[] _sniSpnBuffer) => SNINativeMethodWrapper.SNISecGenClientContext(Handle, receivedBuff, receivedLength, sendBuff, ref sendLength, _sniSpnBuffer); - internal override uint WaitForSSLHandShakeToComplete() - => SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining()); + internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) + => SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining(), out protocolVersion); internal override void DisposePacketCache() { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 807847f171..66eff3cdea 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -417,7 +417,10 @@ $(SystemSecurityCryptographyPrimitivesVersion) - + + $(MicrosoftDataSqlClientSniVersion) + + $(MicrosoftDataSqlClientSniVersion) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index 90a539b1e7..7ae6bc2ebc 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -442,7 +442,7 @@ internal struct SNI_Error internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index d97a5aa2bd..bd53ff4bb0 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1199,7 +1199,9 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(SqlAuthenticationMethod // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete // before calling SNISecGenClientContext). - error = SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(_physicalStateObj.Handle, _physicalStateObj.GetTimeoutRemaining()); + error = SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(_physicalStateObj.Handle, _physicalStateObj.GetTimeoutRemaining(), out uint protocolVersion); + Console.WriteLine(protocolVersion); //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 + if (error != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 0d9788c5bb..22be0d9a27 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -9,25 +9,45 @@ MIT https://aka.ms/sqlclientproject dotnet.png - Provides the data provider for SQL Server. These classes provide access to versions of SQL Server and encapsulate database-specific protocols, including tabular data stream (TDS) - -Commonly Used Types: -Microsoft.Data.SqlClient.SqlConnection -Microsoft.Data.SqlClient.SqlException -Microsoft.Data.SqlClient.SqlParameter -Microsoft.Data.SqlClient.SqlDataReader -Microsoft.Data.SqlClient.SqlCommand -Microsoft.Data.SqlClient.SqlTransaction -Microsoft.Data.SqlClient.SqlParameterCollection -Microsoft.Data.SqlClient.SqlClientFactory - -When using NuGet 3.x this package requires at least version 3.4. + + Provides the data provider for SQL Server. These classes provide access to versions of SQL Server and encapsulate database-specific protocols, including tabular data stream (TDS) + + Commonly Used Types: + Microsoft.Data.SqlClient.SqlConnection + Microsoft.Data.SqlClient.SqlException + Microsoft.Data.SqlClient.SqlParameter + Microsoft.Data.SqlClient.SqlDataReader + Microsoft.Data.SqlClient.SqlCommand + Microsoft.Data.SqlClient.SqlTransaction + Microsoft.Data.SqlClient.SqlParameterCollection + Microsoft.Data.SqlClient.SqlClientFactory + + When using NuGet 3.x this package requires at least version 3.4. + https://go.microsoft.com/fwlink/?linkid=2090501 © Microsoft Corporation. All rights reserved. sqlclient microsoft.data.sqlclient - - + + + + + + + + + + + + + + + + + + + + @@ -74,24 +94,24 @@ When using NuGet 3.x this package requires at least version 3.4. - - - + + + - - - + + + - - - + + + - - - + + + From a997dc6a0acefa13ac8fd40f51ca71c6875f0fd4 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 13 May 2020 21:50:36 -0700 Subject: [PATCH 11/26] Added NetCore protocol warning draft --- .../Microsoft/Data/SqlClient/SNI/SNIHandle.cs | 2 +- .../Data/SqlClient/SNI/SNIMarsConnection.cs | 2 +- .../Data/SqlClient/SNI/SNIMarsHandle.cs | 2 +- .../Data/SqlClient/SNI/SNINpHandle.cs | 4 +- .../Data/SqlClient/SNI/SNITcpHandle.cs | 4 +- .../Data/SqlClient/TdsParser.Unix.cs | 3 +- .../Data/SqlClient/TdsParser.Windows.cs | 5 +- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 23 ++++++- .../Data/SqlClient/TdsParserStateObject.cs | 2 +- .../SqlClient/TdsParserStateObjectManaged.cs | 2 +- .../SqlClient/TdsParserStateObjectNative.cs | 62 ++++++++++++++++++- 11 files changed, 91 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs index 1f9caa8afb..3190879d26 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs @@ -91,7 +91,7 @@ internal abstract class SNIHandle /// /// Gets a value that indicates the security protocol used to authenticate this connection. /// - public virtual uint ProtocolVersion { get; } = 0; + public virtual int ProtocolVersion { get; } = 0; #if DEBUG /// /// Test handle for killing underlying connection diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs index 11f3544f7a..b2618163a5 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsConnection.cs @@ -35,7 +35,7 @@ public Guid ConnectionId } } - public uint ProtocolVersion => (uint)_lowerHandle.ProtocolVersion; + public int ProtocolVersion => _lowerHandle.ProtocolVersion; /// /// Constructor diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs index 3089c08112..a0ff0e4a19 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIMarsHandle.cs @@ -46,7 +46,7 @@ internal sealed class SNIMarsHandle : SNIHandle public override int ReserveHeaderSize => SNISMUXHeader.HEADER_LENGTH; - public override uint ProtocolVersion => _connection.ProtocolVersion; + public override int ProtocolVersion => _connection.ProtocolVersion; /// /// Dispose object diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 7bfc5cebf3..da994254e3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -120,13 +120,13 @@ public override uint Status } } - public override uint ProtocolVersion + public override int ProtocolVersion { get { try { - return (uint)_sslStream.SslProtocol; + return (int)_sslStream.SslProtocol; } catch { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index 2e9aa2e3a2..e1703968ef 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -93,13 +93,13 @@ public override uint Status } } - public override uint ProtocolVersion + public override int ProtocolVersion { get { try { - return (uint)_sslStream.SslProtocol; + return (int)_sslStream.SslProtocol; } catch { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Unix.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Unix.cs index 73eb6fd93f..1c875f5813 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Unix.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Unix.cs @@ -18,10 +18,9 @@ private void LoadSSPILibrary() // No - Op } - private void WaitForSSLHandShakeToComplete(ref uint error) + private void WaitForSSLHandShakeToComplete(ref uint error, ref int protocolVersion) { // No - Op - } private SNIErrorDetails GetSniErrorDetails() diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs index 1903a8fcc6..d5ddb5d47d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs @@ -75,11 +75,8 @@ private void LoadSSPILibrary() } } - private void WaitForSSLHandShakeToComplete(ref uint error, out uint protocolVersion) + private void WaitForSSLHandShakeToComplete(ref uint error, ref int protocolVersion) { - protocolVersion = 0; - if (TdsParserStateObjectFactory.UseManagedSNI) - return; // in the case where an async connection is made, encryption is used and Windows Authentication is used, // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index c94e43398e..b31b6ddc56 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Security.Authentication; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -900,9 +901,25 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus ThrowExceptionAndWarning(_physicalStateObj); } - //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 - WaitForSSLHandShakeToComplete(ref error, out uint protocolVersion); - Console.WriteLine(protocolVersion); + int protocolVersion = 0; + WaitForSSLHandShakeToComplete(ref error, ref protocolVersion); + + string warning = string.Empty; + SslProtocols protocol = (SslProtocols)protocolVersion; +#pragma warning disable CS0618 // Type or member is obsolete : SSL is depricated + if ((protocol & (SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls)) == protocol) +#pragma warning restore CS0618 // Type or member is obsolete : SSL is depricated + { //TODO: add the message to the resources! + warning = string.Format("Security warning: {0} has been superseded by the TLS protocol and is provided for backward compatibility only.", protocol.ToString()); + ConsoleColor foreground = Console.ForegroundColor; + ConsoleColor background = Console.BackgroundColor; + Console.ForegroundColor = ConsoleColor.Yellow; + Console.BackgroundColor = ConsoleColor.Black; + Console.Out.WriteLine(warning); + SqlClientEventSource.Log.TraceEvent(" {0}, {1}", ObjectID, warning); + Console.ForegroundColor = foreground; + Console.BackgroundColor = background; + } // create a new packet encryption changes the internal packet size _physicalStateObj.ClearAllWritePackets(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index bfe1a5bf78..03c691cbd1 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -774,7 +774,7 @@ private void ResetCancelAndProcessAttention() internal abstract uint EnableSsl(ref uint info); - internal abstract uint WaitForSSLHandShakeToComplete(out uint protocolVersion); + internal abstract uint WaitForSSLHandShakeToComplete(out int protocolVersion); internal abstract void Dispose(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs index 88f60bf700..7faa50a3a7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs @@ -204,7 +204,7 @@ internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint recei return 0; } - internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) + internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) { protocolVersion = Handle.ProtocolVersion; return 0; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index aa2d532c65..3ef5a174ee 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Security.Authentication; using System.Threading.Tasks; using Microsoft.Data.Common; @@ -13,6 +14,24 @@ namespace Microsoft.Data.SqlClient { internal class TdsParserStateObjectNative : TdsParserStateObject { + // ptotocol versions from native sni + private enum NativeProtocols + { + SP_PROT_SSL2_SERVER = 0x00000004, + SP_PROT_SSL2_CLIENT = 0x00000008, + SP_PROT_SSL3_SERVER = 0x00000010, + SP_PROT_SSL3_CLIENT = 0x00000020, + SP_PROT_TLS1_0_SERVER = 0x00000040, + SP_PROT_TLS1_0_CLIENT = 0x00000080, + SP_PROT_TLS1_1_SERVER = 0x00000100, + SP_PROT_TLS1_1_CLIENT = 0x00000200, + SP_PROT_TLS1_2_SERVER = 0x00000400, + SP_PROT_TLS1_2_CLIENT = 0x00000800, + SP_PROT_TLS1_3_SERVER = 0x00001000, + SP_PROT_TLS1_3_CLIENT = 0x00002000, + Undefined = 0x0 + } + private SNIHandle _sessionHandle = null; // the SNI handle we're to work on private SNIPacket _sniPacket = null; // Will have to re-vamp this for MARS @@ -310,8 +329,47 @@ internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint receivedLength, ref byte[] sendBuff, ref uint sendLength, byte[] _sniSpnBuffer) => SNINativeMethodWrapper.SNISecGenClientContext(Handle, receivedBuff, receivedLength, sendBuff, ref sendLength, _sniSpnBuffer); - internal override uint WaitForSSLHandShakeToComplete(out uint protocolVersion) - => SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining(), out protocolVersion); + internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) + { + uint returnValue = SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining(), out uint nativeProtocolVersion); + + switch ((NativeProtocols)nativeProtocolVersion) + { + case NativeProtocols.SP_PROT_SSL2_SERVER: + case NativeProtocols.SP_PROT_SSL2_CLIENT: +#pragma warning disable CS0618 // Type or member is obsolete : SSL is depricated + protocolVersion = (int)SslProtocols.Ssl2; + break; + case NativeProtocols.SP_PROT_SSL3_SERVER: + case NativeProtocols.SP_PROT_SSL3_CLIENT: + protocolVersion = (int)SslProtocols.Ssl3; +#pragma warning restore CS0618 // Type or member is obsolete : SSL is depricated + break; + case NativeProtocols.SP_PROT_TLS1_0_SERVER: + case NativeProtocols.SP_PROT_TLS1_0_CLIENT: + protocolVersion = (int)SslProtocols.Tls; + break; + case NativeProtocols.SP_PROT_TLS1_1_SERVER: + case NativeProtocols.SP_PROT_TLS1_1_CLIENT: + protocolVersion = (int)SslProtocols.Tls11; + break; + case NativeProtocols.SP_PROT_TLS1_2_SERVER: + case NativeProtocols.SP_PROT_TLS1_2_CLIENT: + protocolVersion = (int)SslProtocols.Tls12; + break; + /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later + * Our driver does not support this version yet! + case NativeProtocols.SP_PROT_TLS1_3_SERVER: + case NativeProtocols.SP_PROT_TLS1_3_CLIENT: + protocolVersion = (int)SslProtocols.Tls13; + break; + */ + default: + protocolVersion = (int)SslProtocols.None; + break; + } + return returnValue; + } internal override void DisposePacketCache() { From cc7c620afd908e723bdde06cf1de475ad7c0f616 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Fri, 15 May 2020 11:22:43 -0700 Subject: [PATCH 12/26] NetFx SNI changes for auto-load --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 4 + .../Interop/SNINativeManagedWrapperX64.cs | 126 ++++++++ .../Interop/SNINativeManagedWrapperX86.cs | 126 ++++++++ .../Data/Interop/SNINativeMethodWrapper.cs | 301 +++++++++++++----- 4 files changed, 473 insertions(+), 84 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs create mode 100644 src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 807847f171..adc1a2b62c 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -194,6 +194,8 @@ + + @@ -419,6 +421,8 @@ $(MicrosoftDataSqlClientSniVersion) + All + runtime; build; native; contentfiles; analyzers; buildtransitive $(MicrosoftIdentityClientVersion) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs new file mode 100644 index 0000000000..17c9e196d1 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs @@ -0,0 +1,126 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using static Microsoft.Data.SqlClient.SNINativeMethodWrapper; + +namespace Microsoft.Data.SqlClient +{ + internal static class SNINativeManagedWrapperX64 + { + private const string SNI = "Microsoft.Data.SqlClient.sni.x64.dll"; + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] + internal static extern uint SNIAddProvider(SNIHandle pConn, ProviderEnum ProvNum, [In] ref uint pInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] + internal static extern uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref SNICTAIPProviderInfo pInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] + internal static extern uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref AuthProviderInfo pInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNICheckConnectionWrapper")] + internal static extern uint SNICheckConnection([In] SNIHandle pConn); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNICloseWrapper")] + internal static extern uint SNIClose(IntPtr pConn); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern void SNIGetLastError(out SNI_Error pErrorStruct); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern void SNIPacketRelease(IntPtr pPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIPacketResetWrapper")] + internal static extern void SNIPacketReset([In] SNIHandle pConn, IOType IOType, SNIPacket pPacket, ConsumerNumber ConsNum); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIQueryInfo(QTypes QType, ref uint pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIQueryInfo(QTypes QType, ref IntPtr pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIReadAsyncWrapper")] + internal static extern uint SNIReadAsync(SNIHandle pConn, ref IntPtr ppNewPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIReadSyncOverAsync(SNIHandle pConn, ref IntPtr ppNewPacket, int timeout); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIRemoveProviderWrapper")] + internal static extern uint SNIRemoveProvider(SNIHandle pConn, ProviderEnum ProvNum); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNISecInitPackage(ref uint pcbMaxToken); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISetInfoWrapper")] + internal static extern uint SNISetInfo(SNIHandle pConn, QTypes QType, [In] ref uint pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNITerminate(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint GetSniMaxComposedSpnLength(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out Guid pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, [MarshalAs(UnmanagedType.Bool)] out bool pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, ref IntPtr pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIInitialize")] + internal static extern uint SNIInitialize([In] IntPtr pmo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIOpenWrapper( + [In] ref Sni_Consumer_Info pConsumerInfo, + [MarshalAs(UnmanagedType.LPWStr)] string szConnect, + [In] SNIHandle pConn, + out IntPtr ppConn, + [MarshalAs(UnmanagedType.Bool)] bool fSync); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr SNIPacketAllocateWrapper([In] SafeHandle pConn, IOType IOType); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIPacketGetDataWrapper([In] IntPtr packet, [In, Out] byte[] readBuffer, uint readBufferLength, out uint dataSize); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe void SNIPacketSetData(SNIPacket pPacket, [In] byte* pbBuf, uint cbBuf); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISecGenClientContextWrapper")] + internal static extern unsafe uint SNISecGenClientContextWrapper( + [In] SNIHandle pConn, + [In, Out] byte[] pIn, + uint cbIn, + [In, Out] byte[] pOut, + [In] ref uint pcbOut, + [MarshalAsAttribute(UnmanagedType.Bool)] out bool pfDone, + byte* szServerInfo, + uint cbServerInfo, + [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszUserName, + [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszPassword); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIWriteAsyncWrapper(SNIHandle pConn, [In] SNIPacket pPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext); + } +} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs new file mode 100644 index 0000000000..4951f1c930 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs @@ -0,0 +1,126 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using static Microsoft.Data.SqlClient.SNINativeMethodWrapper; + +namespace Microsoft.Data.SqlClient +{ + internal static class SNINativeManagedWrapperX86 + { + private const string SNI = "Microsoft.Data.SqlClient.sni.x86.dll"; + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] + internal static extern uint SNIAddProvider(SNIHandle pConn, ProviderEnum ProvNum, [In] ref uint pInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] + internal static extern uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref SNICTAIPProviderInfo pInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] + internal static extern uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref AuthProviderInfo pInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNICheckConnectionWrapper")] + internal static extern uint SNICheckConnection([In] SNIHandle pConn); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNICloseWrapper")] + internal static extern uint SNIClose(IntPtr pConn); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern void SNIGetLastError(out SNI_Error pErrorStruct); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern void SNIPacketRelease(IntPtr pPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIPacketResetWrapper")] + internal static extern void SNIPacketReset([In] SNIHandle pConn, IOType IOType, SNIPacket pPacket, ConsumerNumber ConsNum); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIQueryInfo(QTypes QType, ref uint pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIQueryInfo(QTypes QType, ref IntPtr pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIReadAsyncWrapper")] + internal static extern uint SNIReadAsync(SNIHandle pConn, ref IntPtr ppNewPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIReadSyncOverAsync(SNIHandle pConn, ref IntPtr ppNewPacket, int timeout); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIRemoveProviderWrapper")] + internal static extern uint SNIRemoveProvider(SNIHandle pConn, ProviderEnum ProvNum); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNISecInitPackage(ref uint pcbMaxToken); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISetInfoWrapper")] + internal static extern uint SNISetInfo(SNIHandle pConn, QTypes QType, [In] ref uint pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNITerminate(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint GetSniMaxComposedSpnLength(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out Guid pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, [MarshalAs(UnmanagedType.Bool)] out bool pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, ref IntPtr pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIInitialize")] + internal static extern uint SNIInitialize([In] IntPtr pmo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIOpenWrapper( + [In] ref Sni_Consumer_Info pConsumerInfo, + [MarshalAs(UnmanagedType.LPWStr)] string szConnect, + [In] SNIHandle pConn, + out IntPtr ppConn, + [MarshalAs(UnmanagedType.Bool)] bool fSync); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr SNIPacketAllocateWrapper([In] SafeHandle pConn, IOType IOType); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIPacketGetDataWrapper([In] IntPtr packet, [In, Out] byte[] readBuffer, uint readBufferLength, out uint dataSize); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe void SNIPacketSetData(SNIPacket pPacket, [In] byte* pbBuf, uint cbBuf); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISecGenClientContextWrapper")] + internal static extern unsafe uint SNISecGenClientContextWrapper( + [In] SNIHandle pConn, + [In, Out] byte[] pIn, + uint cbIn, + [In, Out] byte[] pOut, + [In] ref uint pcbOut, + [MarshalAsAttribute(UnmanagedType.Bool)] out bool pfDone, + byte* szServerInfo, + uint cbServerInfo, + [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszUserName, + [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszPassword); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIWriteAsyncWrapper(SNIHandle pConn, [In] SNIPacket pPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext); + } +} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index 90a539b1e7..499b29b4d3 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -18,9 +18,8 @@ namespace Microsoft.Data.SqlClient { internal static class SNINativeMethodWrapper { - private const string SNI = "Microsoft.Data.SqlClient.SNI.dll"; - private static int s_sniMaxComposedSpnLength = -1; + private static readonly bool s_is64bitProcess = Environment.Is64BitProcess; private const int SniOpenTimeOut = -1; // infinite @@ -52,20 +51,6 @@ internal static class SNINativeMethodWrapper internal const int LocalDBFailedToLoadDll = 56; internal const int LocalDBBadRuntime = 57; - static SNINativeMethodWrapper() - { - var localPath = new Uri(typeof(SNINativeMethodWrapper).Assembly.CodeBase).LocalPath; - var localFolder = Path.GetDirectoryName(localPath); - var subfolder = Environment.Is64BitProcess ? "\\x64\\" : "\\x86\\"; - - IntPtr pDll = LoadLibrary(localFolder + subfolder + SNI); - if (pDll == IntPtr.Zero) - { - throw new System.ComponentModel.Win32Exception("Failed to load " + localFolder + subfolder + SNI, - new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error())); - } - } - internal static int SniMaxComposedSpnLength { get @@ -333,7 +318,7 @@ internal enum TransparentNetworkResolutionMode : byte }; [StructLayout(LayoutKind.Sequential)] - private struct Sni_Consumer_Info + internal struct Sni_Consumer_Info { public int DefaultUserDataLength; public IntPtr ConsumerKey; @@ -347,7 +332,7 @@ private struct Sni_Consumer_Info } [StructLayout(LayoutKind.Sequential)] - private unsafe struct SNI_CLIENT_CONSUMER_INFO + internal unsafe struct SNI_CLIENT_CONSUMER_INFO { public Sni_Consumer_Info ConsumerInfo; [MarshalAs(UnmanagedType.LPWStr)] @@ -393,97 +378,228 @@ internal struct SNI_Error [DllImport("secur32.dll", ExactSpelling = true, SetLastError = true)] internal static extern uint QueryContextAttributes(ref CredHandle contextHandle, [In] ContextAttribute attribute, [In] IntPtr buffer); - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] - internal static extern uint SNIAddProvider(SNIHandle pConn, ProviderEnum ProvNum, [In] ref uint pInfo); + internal static uint SNIAddProvider(SNIHandle pConn, ProviderEnum ProvNum, [In] ref uint pInfo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIAddProvider(pConn, ProvNum, ref pInfo) : + SNINativeManagedWrapperX86.SNIAddProvider(pConn, ProvNum, ref pInfo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] - internal static extern uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref SNICTAIPProviderInfo pInfo); + internal static uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref SNICTAIPProviderInfo pInfo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo) : + SNINativeManagedWrapperX86.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] - internal static extern uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref AuthProviderInfo pInfo); + internal static uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref AuthProviderInfo pInfo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo) : + SNINativeManagedWrapperX86.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNICheckConnectionWrapper")] - internal static extern uint SNICheckConnection([In] SNIHandle pConn); + internal static uint SNICheckConnection([In] SNIHandle pConn) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNICheckConnection(pConn) : + SNINativeManagedWrapperX86.SNICheckConnection(pConn); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNICloseWrapper")] - internal static extern uint SNIClose(IntPtr pConn); + internal static uint SNIClose(IntPtr pConn) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIClose(pConn) : + SNINativeManagedWrapperX86.SNIClose(pConn); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - internal static extern void SNIGetLastError(out SNI_Error pErrorStruct); + internal static void SNIGetLastError(out SNI_Error pErrorStruct) + { + if (s_is64bitProcess) + { + SNINativeManagedWrapperX64.SNIGetLastError(out pErrorStruct); + } + else + { + SNINativeManagedWrapperX86.SNIGetLastError(out pErrorStruct); + } + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - internal static extern void SNIPacketRelease(IntPtr pPacket); + internal static void SNIPacketRelease(IntPtr pPacket) + { + if (s_is64bitProcess) + { + SNINativeManagedWrapperX64.SNIPacketRelease(pPacket); + } + else + { + SNINativeManagedWrapperX86.SNIPacketRelease(pPacket); + } + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIPacketResetWrapper")] - internal static extern void SNIPacketReset([In] SNIHandle pConn, IOType IOType, SNIPacket pPacket, ConsumerNumber ConsNum); + internal static void SNIPacketReset([In] SNIHandle pConn, IOType IOType, SNIPacket pPacket, ConsumerNumber ConsNum) + { + if (s_is64bitProcess) + { + SNINativeManagedWrapperX64.SNIPacketReset(pConn, IOType, pPacket, ConsNum); + } + else + { + SNINativeManagedWrapperX86.SNIPacketReset(pConn, IOType, pPacket, ConsNum); + } + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint SNIQueryInfo(QTypes QType, ref uint pbQInfo); + internal static uint SNIQueryInfo(QTypes QType, ref uint pbQInfo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIQueryInfo(QType, ref pbQInfo) : + SNINativeManagedWrapperX86.SNIQueryInfo(QType, ref pbQInfo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint SNIQueryInfo(QTypes QType, ref IntPtr pbQInfo); + internal static uint SNIQueryInfo(QTypes QType, ref IntPtr pbQInfo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIQueryInfo(QType, ref pbQInfo) : + SNINativeManagedWrapperX86.SNIQueryInfo(QType, ref pbQInfo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIReadAsyncWrapper")] - internal static extern uint SNIReadAsync(SNIHandle pConn, ref IntPtr ppNewPacket); + internal static uint SNIReadAsync(SNIHandle pConn, ref IntPtr ppNewPacket) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIReadAsync(pConn, ref ppNewPacket) : + SNINativeManagedWrapperX86.SNIReadAsync(pConn, ref ppNewPacket); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint SNIReadSyncOverAsync(SNIHandle pConn, ref IntPtr ppNewPacket, int timeout); + internal static uint SNIReadSyncOverAsync(SNIHandle pConn, ref IntPtr ppNewPacket, int timeout) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIReadSyncOverAsync(pConn, ref ppNewPacket, timeout) : + SNINativeManagedWrapperX86.SNIReadSyncOverAsync(pConn, ref ppNewPacket, timeout); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIRemoveProviderWrapper")] - internal static extern uint SNIRemoveProvider(SNIHandle pConn, ProviderEnum ProvNum); + internal static uint SNIRemoveProvider(SNIHandle pConn, ProviderEnum ProvNum) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIRemoveProvider(pConn, ProvNum) : + SNINativeManagedWrapperX86.SNIRemoveProvider(pConn, ProvNum); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint SNISecInitPackage(ref uint pcbMaxToken); + internal static uint SNISecInitPackage(ref uint pcbMaxToken) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNISecInitPackage(ref pcbMaxToken) : + SNINativeManagedWrapperX86.SNISecInitPackage(ref pcbMaxToken); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISetInfoWrapper")] - internal static extern uint SNISetInfo(SNIHandle pConn, QTypes QType, [In] ref uint pbQInfo); + internal static uint SNISetInfo(SNIHandle pConn, QTypes QType, [In] ref uint pbQInfo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNISetInfo(pConn, QType, ref pbQInfo) : + SNINativeManagedWrapperX86.SNISetInfo(pConn, QType, ref pbQInfo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint SNITerminate(); + internal static uint SNITerminate() + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNITerminate() : + SNINativeManagedWrapperX86.SNITerminate(); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + internal static uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds) : + SNINativeManagedWrapperX86.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); + internal static uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.UnmanagedIsTokenRestricted(token, out isRestricted) : + SNINativeManagedWrapperX86.UnmanagedIsTokenRestricted(token, out isRestricted); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint GetSniMaxComposedSpnLength(); + private static uint GetSniMaxComposedSpnLength() + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.GetSniMaxComposedSpnLength() : + SNINativeManagedWrapperX86.GetSniMaxComposedSpnLength(); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out Guid pbQInfo); + private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out Guid pbQInfo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out pbQInfo) : + SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, [MarshalAs(UnmanagedType.Bool)] out bool pbQInfo); + private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, [MarshalAs(UnmanagedType.Bool)] out bool pbQInfo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out pbQInfo) : + SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, ref IntPtr pbQInfo); + private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, ref IntPtr pbQInfo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, ref pbQInfo) : + SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, ref pbQInfo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIInitialize")] - private static extern uint SNIInitialize([In] IntPtr pmo); + private static uint SNIInitialize([In] IntPtr pmo) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIInitialize(pmo) : + SNINativeManagedWrapperX86.SNIInitialize(pmo); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); + private static uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIOpenSyncExWrapper(ref pClientConsumerInfo, out ppConn) : + SNINativeManagedWrapperX86.SNIOpenSyncExWrapper(ref pClientConsumerInfo, out ppConn); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIOpenWrapper( + private static uint SNIOpenWrapper( [In] ref Sni_Consumer_Info pConsumerInfo, [MarshalAs(UnmanagedType.LPWStr)] string szConnect, [In] SNIHandle pConn, out IntPtr ppConn, - [MarshalAs(UnmanagedType.Bool)] bool fSync); + [MarshalAs(UnmanagedType.Bool)] bool fSync) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIOpenWrapper(ref pConsumerInfo, szConnect, pConn, out ppConn, fSync) : + SNINativeManagedWrapperX86.SNIOpenWrapper(ref pConsumerInfo, szConnect, pConn, out ppConn, fSync); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr SNIPacketAllocateWrapper([In] SafeHandle pConn, IOType IOType); + private static IntPtr SNIPacketAllocateWrapper([In] SafeHandle pConn, IOType IOType) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIPacketAllocateWrapper(pConn, IOType) : + SNINativeManagedWrapperX86.SNIPacketAllocateWrapper(pConn, IOType); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIPacketGetDataWrapper([In] IntPtr packet, [In, Out] byte[] readBuffer, uint readBufferLength, out uint dataSize); + private static uint SNIPacketGetDataWrapper([In] IntPtr packet, [In, Out] byte[] readBuffer, uint readBufferLength, out uint dataSize) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIPacketGetDataWrapper(packet, readBuffer, readBufferLength, out dataSize) : + SNINativeManagedWrapperX86.SNIPacketGetDataWrapper(packet, readBuffer, readBufferLength, out dataSize); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern unsafe void SNIPacketSetData(SNIPacket pPacket, [In] byte* pbBuf, uint cbBuf); + private static unsafe void SNIPacketSetData(SNIPacket pPacket, [In] byte* pbBuf, uint cbBuf) + { + if (s_is64bitProcess) + { + SNINativeManagedWrapperX64.SNIPacketSetData(pPacket, pbBuf, cbBuf); + } + else + { + SNINativeManagedWrapperX86.SNIPacketSetData(pPacket, pbBuf, cbBuf); + } + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISecGenClientContextWrapper")] - private static extern unsafe uint SNISecGenClientContextWrapper( + private static unsafe uint SNISecGenClientContextWrapper( [In] SNIHandle pConn, [In, Out] byte[] pIn, uint cbIn, @@ -493,16 +609,33 @@ private static extern unsafe uint SNISecGenClientContextWrapper( byte* szServerInfo, uint cbServerInfo, [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszUserName, - [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszPassword); + [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszPassword) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNISecGenClientContextWrapper(pConn, pIn, cbIn, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword) : + SNINativeManagedWrapperX86.SNISecGenClientContextWrapper(pConn, pIn, cbIn, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIWriteAsyncWrapper(SNIHandle pConn, [In] SNIPacket pPacket); + private static uint SNIWriteAsyncWrapper(SNIHandle pConn, [In] SNIPacket pPacket) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIWriteAsyncWrapper(pConn, pPacket) : + SNINativeManagedWrapperX86.SNIWriteAsyncWrapper(pConn, pPacket); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket); + private static uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIWriteSyncOverAsync(pConn, pPacket) : + SNINativeManagedWrapperX86.SNIWriteSyncOverAsync(pConn, pPacket); + } - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext); + private static IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext) + { + return s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIClientCertificateFallbackWrapper(pCallbackContext) : + SNINativeManagedWrapperX86.SNIClientCertificateFallbackWrapper(pCallbackContext); + } #endregion internal static uint SNISecGetServerCertificate(SNIHandle pConnectionObject, ref X509Certificate2 certificate) From 962b8e4db0259767caed98e219984937c68c07f3 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Fri, 15 May 2020 15:01:29 -0700 Subject: [PATCH 13/26] Capitalize --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 95a1e7d07c..9f64f4b6e5 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -665,7 +665,7 @@ - + From 9216b09c63f15494cf0f9451594ac66690cfa598 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Sun, 17 May 2020 18:41:17 -0700 Subject: [PATCH 14/26] Throw unsecure protocol warning at NetCore --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 9 ++-- .../Data/SqlClient/TdsParserHelperClasses.cs | 51 +++++++++++++++++++ .../SqlClient/TdsParserStateObjectNative.cs | 9 ++-- .../netcore/src/Resources/SR.Designer.cs | 9 ++++ .../netcore/src/Resources/SR.resx | 5 +- 5 files changed, 73 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index b31b6ddc56..83ee4ed3f8 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -904,13 +904,10 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus int protocolVersion = 0; WaitForSSLHandShakeToComplete(ref error, ref protocolVersion); - string warning = string.Empty; SslProtocols protocol = (SslProtocols)protocolVersion; -#pragma warning disable CS0618 // Type or member is obsolete : SSL is depricated - if ((protocol & (SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls)) == protocol) -#pragma warning restore CS0618 // Type or member is obsolete : SSL is depricated - { //TODO: add the message to the resources! - warning = string.Format("Security warning: {0} has been superseded by the TLS protocol and is provided for backward compatibility only.", protocol.ToString()); + string warning = protocol.GetProtocolWarning(); + if(!string.IsNullOrEmpty(warning)) + { ConsoleColor foreground = Console.ForegroundColor; ConsoleColor background = Console.BackgroundColor; Console.ForegroundColor = ConsoleColor.Yellow; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index 1e24817b85..cdedf42de8 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using System.Globalization; using System.Security; +using System.Security.Authentication; using System.Text; using Microsoft.Data.Common; using Microsoft.Data.SqlTypes; @@ -917,4 +918,54 @@ private void ParseMultipartName() internal static readonly MultiPartTableName Null = new MultiPartTableName(new string[] { null, null, null, null }); } + + internal static class SslProtocolsHelper + { + private static string ToFriendlyName(this SslProtocols protocol) + { + string name ; + + switch (protocol) + { +#pragma warning disable CS0618 // Type or member is obsolete: SSL is depricated + case SslProtocols.Ssl2: + name = "SSL 2"; + break; + case SslProtocols.Ssl3: + name = "SSL 3"; + break; +#pragma warning restore CS0618 // Type or member is obsolete: SSL is depricated + /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later + * This driver does not support this version yet! + case SslProtocols.Tls13: + name = "TLS 1.3"; + break; + */ + case SslProtocols.Tls: + name = "TLS 1.0"; + break; + case SslProtocols.Tls11: + name = "TLS 1.1"; + break; + case SslProtocols.Tls12: + name = "TLS 1.2"; + break; + default: + name = protocol.ToString(); + break; + }; + return name; + } + public static string GetProtocolWarning(this SslProtocols protocol) + { + string message = string.Empty; +#pragma warning disable CS0618 // Type or member is obsolete : SSL is depricated + if ((protocol & (SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11)) == protocol) +#pragma warning restore CS0618 // Type or member is obsolete : SSL is depricated + { + message = SRHelper.Format(SR.SEC_ProtocolWarning, protocol.ToFriendlyName()); + } + return message; + } + } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index 3ef5a174ee..17ec9fb7da 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -15,6 +15,7 @@ namespace Microsoft.Data.SqlClient internal class TdsParserStateObjectNative : TdsParserStateObject { // ptotocol versions from native sni + [Flags] private enum NativeProtocols { SP_PROT_SSL2_SERVER = 0x00000004, @@ -29,7 +30,7 @@ private enum NativeProtocols SP_PROT_TLS1_2_CLIENT = 0x00000800, SP_PROT_TLS1_3_SERVER = 0x00001000, SP_PROT_TLS1_3_CLIENT = 0x00002000, - Undefined = 0x0 + SP_PROT_NONE = 0x0 } private SNIHandle _sessionHandle = null; // the SNI handle we're to work on @@ -358,15 +359,17 @@ internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) protocolVersion = (int)SslProtocols.Tls12; break; /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later - * Our driver does not support this version yet! + * This driver does not support this version yet! case NativeProtocols.SP_PROT_TLS1_3_SERVER: case NativeProtocols.SP_PROT_TLS1_3_CLIENT: protocolVersion = (int)SslProtocols.Tls13; break; */ - default: + case NativeProtocols.SP_PROT_NONE: protocolVersion = (int)SslProtocols.None; break; + default: + throw new InvalidOperationException("Unknown protocol."); } return returnValue; } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs index 6e66321a54..62533f31c7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs @@ -1428,6 +1428,15 @@ internal static string PlatformNotSupported_DataSqlClient { } } + /// + /// Looks up a localized string similar to Security Warning: The '{0}' is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later.. + /// + internal static string SEC_ProtocolWarning { + get { + return ResourceManager.GetString("SEC_ProtocolWarning", resourceCulture); + } + } + /// /// Looks up a localized string similar to I/O Error detected in read/write operation. /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx index d4a5797c0e..c2327fead7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx @@ -1863,4 +1863,7 @@ The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}]. - + + Security Warning: The {0} is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later. + + \ No newline at end of file From eefd8eddbd86fcc3670848c103d20ae3307c7462 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Sun, 17 May 2020 18:42:21 -0700 Subject: [PATCH 15/26] Throw unsecure protocol warning at NetFx --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 14 +++- .../Data/SqlClient/TdsParserHelperClasses.cs | 74 +++++++++++++++++++ .../netfx/src/Resources/Strings.Designer.cs | 9 +++ .../netfx/src/Resources/Strings.resx | 3 + 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index bd53ff4bb0..61fe6584bb 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1200,7 +1200,6 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(SqlAuthenticationMethod // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete // before calling SNISecGenClientContext). error = SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(_physicalStateObj.Handle, _physicalStateObj.GetTimeoutRemaining(), out uint protocolVersion); - Console.WriteLine(protocolVersion); //TODO: After discover the protocol version, it must be throw as a warning if it's lower than TLS 1.2 if (error != TdsEnums.SNI_SUCCESS) { @@ -1208,6 +1207,19 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(SqlAuthenticationMethod ThrowExceptionAndWarning(_physicalStateObj); } + string warning = SslProtocolsHelper.GetProtocolWarning(protocolVersion); + if (!string.IsNullOrEmpty(warning)) + { + ConsoleColor foreground = Console.ForegroundColor; + ConsoleColor background = Console.BackgroundColor; + Console.ForegroundColor = ConsoleColor.Yellow; + Console.BackgroundColor = ConsoleColor.Black; + Console.Out.WriteLine(warning); + SqlClientEventSource.Log.TraceEvent(" {0}, {1}", ObjectID, warning); + Console.ForegroundColor = foreground; + Console.BackgroundColor = background; + } + // Validate server certificate // if (serverCallback != null) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index 96eb11c0d2..424a68f42d 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -1421,4 +1421,78 @@ private void ParseMultipartName() internal static readonly MultiPartTableName Null = new MultiPartTableName(new string[] { null, null, null, null }); } + + internal static class SslProtocolsHelper + { + // ptotocol versions from native sni + [Flags] + private enum NativeProtocols + { + SP_PROT_SSL2_SERVER = 0x00000004, + SP_PROT_SSL2_CLIENT = 0x00000008, + SP_PROT_SSL3_SERVER = 0x00000010, + SP_PROT_SSL3_CLIENT = 0x00000020, + SP_PROT_TLS1_0_SERVER = 0x00000040, + SP_PROT_TLS1_0_CLIENT = 0x00000080, + SP_PROT_TLS1_1_SERVER = 0x00000100, + SP_PROT_TLS1_1_CLIENT = 0x00000200, + SP_PROT_TLS1_2_SERVER = 0x00000400, + SP_PROT_TLS1_2_CLIENT = 0x00000800, + SP_PROT_TLS1_3_SERVER = 0x00001000, + SP_PROT_TLS1_3_CLIENT = 0x00002000, + SP_PROT_SSL2 = SP_PROT_SSL2_SERVER | SP_PROT_SSL2_CLIENT, + SP_PROT_SSL3 = SP_PROT_SSL3_SERVER | SP_PROT_SSL3_CLIENT, + SP_PROT_TLS1_0 = SP_PROT_TLS1_0_SERVER | SP_PROT_TLS1_0_CLIENT, + SP_PROT_TLS1_1 = SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_1_CLIENT, + SP_PROT_TLS1_2 = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_2_CLIENT, + SP_PROT_TLS1_3 = SP_PROT_TLS1_3_SERVER | SP_PROT_TLS1_3_CLIENT, + SP_PROT_NONE = 0x0 + } + + private static string ToFriendlyName(this NativeProtocols protocol) + { + string name; + + if ((protocol & NativeProtocols.SP_PROT_SSL2) == protocol) + { + name = "SSL 2"; + } + else if ((protocol & NativeProtocols.SP_PROT_SSL3) == protocol) + { + name = "SSL 3"; + } + else if ((protocol & NativeProtocols.SP_PROT_TLS1_0) == protocol) + { + name = "TLS 1.0"; + } + else if ((protocol & NativeProtocols.SP_PROT_TLS1_1) == protocol) + { + name = "TLS 1.1"; + } + else if ((protocol & NativeProtocols.SP_PROT_TLS1_2) == protocol) + { + name = "TLS 1.2"; + } + else if ((protocol & NativeProtocols.SP_PROT_TLS1_3) == protocol) + { + name = "TLS 1.3"; + } + else + { + throw new InvalidOperationException("Unknown protocol."); + } + return name; + } + + public static string GetProtocolWarning(uint protocol) + { + var nativeProtocol = (NativeProtocols)protocol; + string message = string.Empty; + if ((nativeProtocol & (NativeProtocols.SP_PROT_SSL2 | NativeProtocols.SP_PROT_SSL3 | NativeProtocols.SP_PROT_TLS1_1)) == nativeProtocol) + { + message = StringsHelper.GetString(Strings.SEC_ProtocolWarning, nativeProtocol.ToFriendlyName()); + } + return message; + } + } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs index 0e5f67f488..cff4277ad2 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs @@ -8082,6 +8082,15 @@ internal static string RecordManager_MinimumCapacity { } } + /// + /// Looks up a localized string similar to Security Warning: The '{0}' is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later.. + /// + internal static string SEC_ProtocolWarning { + get { + return ResourceManager.GetString("SEC_ProtocolWarning", resourceCulture); + } + } + /// /// Looks up a localized string similar to I/O Error detected in read/write operation. /// diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx index d6f8ec6e0b..53a9eb0484 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -4530,4 +4530,7 @@ UDT size must be less than {1}, size: {0} + + Security Warning: The {0} is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later. + \ No newline at end of file From 5ccd76363f6094a919a5d9cc100727bd90e14ea8 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 19 May 2020 12:55:49 -0700 Subject: [PATCH 16/26] Update new SNI approach changes --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 5 +---- .../Interop/SNINativeManagedWrapperX64.cs | 2 +- .../Interop/SNINativeManagedWrapperX86.cs | 2 +- .../Data/Interop/SNINativeMethodWrapper.cs | 6 ++--- tools/props/Versions.props | 4 ---- tools/specs/Microsoft.Data.SqlClient.nuspec | 22 ++----------------- 6 files changed, 8 insertions(+), 33 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index e6b7057065..adc1a2b62c 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -419,10 +419,7 @@ $(SystemSecurityCryptographyPrimitivesVersion) - - $(MicrosoftDataSqlClientSniVersion) - - + $(MicrosoftDataSqlClientSniVersion) All runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs index 17c9e196d1..4702e9f117 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs @@ -61,7 +61,7 @@ internal static class SNINativeManagedWrapperX64 internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs index 4951f1c930..198c242553 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs @@ -61,7 +61,7 @@ internal static class SNINativeManagedWrapperX86 internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index 499b29b4d3..fe299cd105 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -505,11 +505,11 @@ internal static uint SNITerminate() SNINativeManagedWrapperX86.SNITerminate(); } - internal static uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds) + internal static uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion) { return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds) : - SNINativeManagedWrapperX86.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds); + SNINativeManagedWrapperX64.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out dwProtocolVersion) : + SNINativeManagedWrapperX86.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out dwProtocolVersion); } internal static uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted) diff --git a/tools/props/Versions.props b/tools/props/Versions.props index f719fa55d3..1db1bc6438 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -61,8 +61,4 @@ 5.0.0-beta.20206.4 2.0.8 - - $(NugetPackageVersion) - $(NugetPackageVersion) - diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 22be0d9a27..7c9597f6d1 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -28,26 +28,8 @@ © Microsoft Corporation. All rights reserved. sqlclient microsoft.data.sqlclient - - - - - - - - - - - - - - - - - - - - + + From ab564cef765f7096d6b89f319d2bd7e1ecedeeeb Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 19 May 2020 13:00:23 -0700 Subject: [PATCH 17/26] Udate NetFx & add net_invalid_enum message --- .../Data/SqlClient/TdsParserHelperClasses.cs | 32 +++++++++++-------- .../netfx/src/Resources/Strings.Designer.cs | 11 ++++++- .../netfx/src/Resources/Strings.resx | 3 ++ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index 424a68f42d..09ee312319 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -1453,33 +1453,37 @@ private static string ToFriendlyName(this NativeProtocols protocol) { string name; - if ((protocol & NativeProtocols.SP_PROT_SSL2) == protocol) + if (protocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_CLIENT) || protocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_SERVER)) { - name = "SSL 2"; + name = "TLS 1.3"; + } + else if (protocol.HasFlag(NativeProtocols.SP_PROT_TLS1_2_CLIENT) || protocol.HasFlag(NativeProtocols.SP_PROT_TLS1_2_SERVER)) + { + name = "TLS 1.2"; } - else if ((protocol & NativeProtocols.SP_PROT_SSL3) == protocol) + else if (protocol.HasFlag(NativeProtocols.SP_PROT_TLS1_1_CLIENT) || protocol.HasFlag(NativeProtocols.SP_PROT_TLS1_1_SERVER)) { - name = "SSL 3"; + name = "TLS 1.1"; } - else if ((protocol & NativeProtocols.SP_PROT_TLS1_0) == protocol) + else if (protocol.HasFlag(NativeProtocols.SP_PROT_TLS1_0_CLIENT) || protocol.HasFlag(NativeProtocols.SP_PROT_TLS1_0_SERVER)) { name = "TLS 1.0"; } - else if ((protocol & NativeProtocols.SP_PROT_TLS1_1) == protocol) + else if (protocol.HasFlag(NativeProtocols.SP_PROT_SSL3_CLIENT) || protocol.HasFlag(NativeProtocols.SP_PROT_SSL3_SERVER)) { - name = "TLS 1.1"; + name = "SSL 3.0"; } - else if ((protocol & NativeProtocols.SP_PROT_TLS1_2) == protocol) + else if (protocol.HasFlag(NativeProtocols.SP_PROT_SSL2_CLIENT) || protocol.HasFlag(NativeProtocols.SP_PROT_SSL2_SERVER)) { - name = "TLS 1.2"; + name = "SSL 2.0"; } - else if ((protocol & NativeProtocols.SP_PROT_TLS1_3) == protocol) + else if(protocol.HasFlag(NativeProtocols.SP_PROT_NONE)) { - name = "TLS 1.3"; + name = "None"; } else { - throw new InvalidOperationException("Unknown protocol."); + throw new ArgumentException(StringsHelper.GetString(StringsHelper.net_invalid_enum, nameof(NativeProtocols)), nameof(NativeProtocols)); } return name; } @@ -1488,9 +1492,9 @@ public static string GetProtocolWarning(uint protocol) { var nativeProtocol = (NativeProtocols)protocol; string message = string.Empty; - if ((nativeProtocol & (NativeProtocols.SP_PROT_SSL2 | NativeProtocols.SP_PROT_SSL3 | NativeProtocols.SP_PROT_TLS1_1)) == nativeProtocol) + if ((nativeProtocol & (NativeProtocols.SP_PROT_SSL2 | NativeProtocols.SP_PROT_SSL3 | NativeProtocols.SP_PROT_TLS1_1)) != NativeProtocols.SP_PROT_NONE) { - message = StringsHelper.GetString(Strings.SEC_ProtocolWarning, nativeProtocol.ToFriendlyName()); + message = StringsHelper.GetString(Strings.SEC_ProtocolWarning, nativeProtocol.ToFriendlyName()); } return message; } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs index cff4277ad2..63323bdf89 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs @@ -7062,6 +7062,15 @@ internal static string NamedSimpleType_InvalidDuplicateNamedSimpleTypeDelaration } } + /// + /// Looks up a localized string similar to The specified value is not valid in the '{0}' enumeration.. + /// + internal static string net_invalid_enum { + get { + return ResourceManager.GetString("net_invalid_enum", resourceCulture); + } + } + /// /// Looks up a localized string similar to DateType column for field '{0}' in schema table is null. DataType must be non-null.. /// @@ -8083,7 +8092,7 @@ internal static string RecordManager_MinimumCapacity { } /// - /// Looks up a localized string similar to Security Warning: The '{0}' is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later.. + /// Looks up a localized string similar to Security Warning: The {0} is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later.. /// internal static string SEC_ProtocolWarning { get { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx index 53a9eb0484..a5683b3595 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -4533,4 +4533,7 @@ Security Warning: The {0} is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later. + + The specified value is not valid in the '{0}' enumeration. + \ No newline at end of file From a708ae3d8459667ca80b6977fc73cf88d6f3a793 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 19 May 2020 13:00:59 -0700 Subject: [PATCH 18/26] Update NetCore --- .../Data/SqlClient/TdsParserHelperClasses.cs | 62 +++++++++-------- .../SqlClient/TdsParserStateObjectNative.cs | 68 +++++++++---------- 2 files changed, 67 insertions(+), 63 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index cdedf42de8..81e16760fa 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -923,44 +923,48 @@ internal static class SslProtocolsHelper { private static string ToFriendlyName(this SslProtocols protocol) { - string name ; + string name; - switch (protocol) + /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later + * This driver does not support this version yet! + if ((protocol & SslProtocols.Tls13) == SslProtocols.Tls13) { + name = "TLS 1.3"; + }*/ + if((protocol & SslProtocols.Tls12) == SslProtocols.Tls12) + { + name = "TLS 1.2"; + } + else if ((protocol & SslProtocols.Tls11) == SslProtocols.Tls11) + { + name = "TLS 1.1"; + } + else if ((protocol & SslProtocols.Tls) == SslProtocols.Tls) + { + name = "TLS 1.0"; + } #pragma warning disable CS0618 // Type or member is obsolete: SSL is depricated - case SslProtocols.Ssl2: - name = "SSL 2"; - break; - case SslProtocols.Ssl3: - name = "SSL 3"; - break; -#pragma warning restore CS0618 // Type or member is obsolete: SSL is depricated - /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later - * This driver does not support this version yet! - case SslProtocols.Tls13: - name = "TLS 1.3"; - break; - */ - case SslProtocols.Tls: - name = "TLS 1.0"; - break; - case SslProtocols.Tls11: - name = "TLS 1.1"; - break; - case SslProtocols.Tls12: - name = "TLS 1.2"; - break; - default: - name = protocol.ToString(); - break; - }; + else if ((protocol & SslProtocols.Ssl3) == SslProtocols.Ssl3) + { + name = "SSL 3.0"; + } + else if ((protocol & SslProtocols.Ssl2) == SslProtocols.Ssl2) +#pragma warning disable CS0618 // Type or member is obsolete: SSL is depricated + { + name = "SSL 2.0"; + } + else + { + name = protocol.ToString(); + } + return name; } public static string GetProtocolWarning(this SslProtocols protocol) { string message = string.Empty; #pragma warning disable CS0618 // Type or member is obsolete : SSL is depricated - if ((protocol & (SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11)) == protocol) + if ((protocol & (SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11)) != SslProtocols.None) #pragma warning restore CS0618 // Type or member is obsolete : SSL is depricated { message = SRHelper.Format(SR.SEC_ProtocolWarning, protocol.ToFriendlyName()); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index 17ec9fb7da..8fff136c2c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -333,43 +333,43 @@ internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint recei internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) { uint returnValue = SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining(), out uint nativeProtocolVersion); - - switch ((NativeProtocols)nativeProtocolVersion) + var nativeProtocol = (NativeProtocols)nativeProtocolVersion; + + /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later + * This driver does not support this version yet! + if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_SERVER)) + { + protocolVersion = (int)SslProtocols.Tls13; + }*/ + if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_2_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_2_SERVER)) + { + protocolVersion = (int)SslProtocols.Tls12; + } + else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_1_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_1_SERVER)) + { + protocolVersion = (int)SslProtocols.Tls11; + } + else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_0_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_0_SERVER)) + { + protocolVersion = (int)SslProtocols.Tls; + } + else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL3_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL3_SERVER)) { - case NativeProtocols.SP_PROT_SSL2_SERVER: - case NativeProtocols.SP_PROT_SSL2_CLIENT: #pragma warning disable CS0618 // Type or member is obsolete : SSL is depricated - protocolVersion = (int)SslProtocols.Ssl2; - break; - case NativeProtocols.SP_PROT_SSL3_SERVER: - case NativeProtocols.SP_PROT_SSL3_CLIENT: - protocolVersion = (int)SslProtocols.Ssl3; + protocolVersion = (int)SslProtocols.Ssl3; + } + else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL2_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL2_SERVER)) + { + protocolVersion = (int)SslProtocols.Ssl2; #pragma warning restore CS0618 // Type or member is obsolete : SSL is depricated - break; - case NativeProtocols.SP_PROT_TLS1_0_SERVER: - case NativeProtocols.SP_PROT_TLS1_0_CLIENT: - protocolVersion = (int)SslProtocols.Tls; - break; - case NativeProtocols.SP_PROT_TLS1_1_SERVER: - case NativeProtocols.SP_PROT_TLS1_1_CLIENT: - protocolVersion = (int)SslProtocols.Tls11; - break; - case NativeProtocols.SP_PROT_TLS1_2_SERVER: - case NativeProtocols.SP_PROT_TLS1_2_CLIENT: - protocolVersion = (int)SslProtocols.Tls12; - break; - /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later - * This driver does not support this version yet! - case NativeProtocols.SP_PROT_TLS1_3_SERVER: - case NativeProtocols.SP_PROT_TLS1_3_CLIENT: - protocolVersion = (int)SslProtocols.Tls13; - break; - */ - case NativeProtocols.SP_PROT_NONE: - protocolVersion = (int)SslProtocols.None; - break; - default: - throw new InvalidOperationException("Unknown protocol."); + } + else if(nativeProtocol.HasFlag(NativeProtocols.SP_PROT_NONE)) + { + protocolVersion = (int)SslProtocols.None; + } + else + { + throw new ArgumentException(SRHelper.Format(SRHelper.net_invalid_enum, nameof(NativeProtocols)), nameof(NativeProtocols)); } return returnValue; } From 0fd42f3a81ef23d1ae7c67efe925e87ed9bd8f96 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 19 May 2020 13:16:54 -0700 Subject: [PATCH 19/26] Revert "Merge branch 'SSL_TLS_WarningMessage' of github.com:DavoudEshtehari/SqlClient into SSL_TLS_WarningMessage" This reverts commit 6345d10823f398ff1c20540f0636d3216892fe4c, reversing changes made to a708ae3d8459667ca80b6977fc73cf88d6f3a793. --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 3384 +++++++++++++++++ tools/specs/Microsoft.Data.SqlClient.nuspec | 22 +- 2 files changed, 3386 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index d86ed23eee..61fe6584bb 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -10220,3 +10220,3387 @@ internal Task TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, int timeout, boo // Take care of releasing the locks if (releaseConnectionLock) + { + task.ContinueWith(_ => + { + _connHandler._parserLock.Release(); + }, TaskScheduler.Default); + releaseConnectionLock = false; + } + + return task; + } + } +#if DEBUG + else + { + Debug.Assert(writeParamTask == null, "Should not have a task when executing sync"); + } +#endif + } // parameter for loop + + // If this is not the last RPC we are sending, add the batch flag + if (ii < (rpcArray.Length - 1)) + { + if (_isYukon) + { + stateObj.WriteByte(TdsEnums.YUKON_RPCBATCHFLAG); + + } + else + { + stateObj.WriteByte(TdsEnums.SHILOH_RPCBATCHFLAG); + } + } + } // rpc for loop + + Task execFlushTask = stateObj.ExecuteFlush(); + Debug.Assert(!sync || execFlushTask == null, "Should not get a task when executing sync"); + if (execFlushTask != null) + { + Task task = null; + + if (completion == null) + { + completion = new TaskCompletionSource(); + task = completion.Task; + } + + bool taskReleaseConnectionLock = releaseConnectionLock; + execFlushTask.ContinueWith(tsk => ExecuteFlushTaskCallback(tsk, stateObj, completion, taskReleaseConnectionLock), TaskScheduler.Default); + + // ExecuteFlushTaskCallback will take care of the locks for us + releaseConnectionLock = false; + + return task; + } + } + catch (Exception e) + { + // UNDONE - should not be catching all exceptions!!! + if (!ADP.IsCatchableExceptionType(e)) + { + throw; + } + + FailureCleanup(stateObj, e); + + throw; + } + FinalizeExecuteRPC(stateObj); + if (completion != null) + { + completion.SetResult(null); + } + return null; + } + catch (Exception e) + { + FinalizeExecuteRPC(stateObj); + if (completion != null) + { + completion.SetException(e); + return null; + } + else + { + throw; + } + } + finally + { + Debug.Assert(firstCall || !releaseConnectionLock, "Shouldn't be releasing locks synchronously after the first call"); + if (releaseConnectionLock) + { + _connHandler._parserLock.Release(); + } + } + } + + private void WriteEnclaveInfo(TdsParserStateObject stateObj, byte[] enclavePackage) + { + //If the server supports enclave computations, write enclave info. + if (TceVersionSupported >= TdsEnums.MIN_TCE_VERSION_WITH_ENCLAVE_SUPPORT) + { + if (enclavePackage != null) + { + //EnclavePackage Length + WriteShort((short)enclavePackage.Length, stateObj); + stateObj.WriteByteArray(enclavePackage, enclavePackage.Length, 0); + } + else + { + //EnclavePackage Length + WriteShort((short)0, stateObj); + } + } + } + + private void FinalizeExecuteRPC(TdsParserStateObject stateObj) + { + stateObj.SniContext = SniContext.Snix_Read; + _asyncWrite = false; + } + + private void TdsExecuteRPC_OnFailure(Exception exc, TdsParserStateObject stateObj) + { + RuntimeHelpers.PrepareConstrainedRegions(); + try + { +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + FailureCleanup(stateObj, exc); + } +#if DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (System.OutOfMemoryException) + { + _connHandler.DoomThisConnection(); + throw; + } + catch (System.StackOverflowException) + { + _connHandler.DoomThisConnection(); + throw; + } + catch (System.Threading.ThreadAbortException) + { + _connHandler.DoomThisConnection(); + throw; + } + } + + private void ExecuteFlushTaskCallback(Task tsk, TdsParserStateObject stateObj, TaskCompletionSource completion, bool releaseConnectionLock) + { + try + { + FinalizeExecuteRPC(stateObj); + if (tsk.Exception != null) + { + Exception exc = tsk.Exception.InnerException; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + FailureCleanup(stateObj, tsk.Exception); + } +#if DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (System.OutOfMemoryException e) + { + _connHandler.DoomThisConnection(); + completion.SetException(e); + throw; + } + catch (System.StackOverflowException e) + { + _connHandler.DoomThisConnection(); + completion.SetException(e); + throw; + } + catch (System.Threading.ThreadAbortException e) + { + _connHandler.DoomThisConnection(); + completion.SetException(e); + throw; + } + catch (Exception e) + { + exc = e; + } + completion.SetException(exc); + } + else + { + completion.SetResult(null); + } + } + finally + { + if (releaseConnectionLock) + { + _connHandler._parserLock.Release(); + } + } + } + + + private void WriteParameterName(string parameterName, TdsParserStateObject stateObj) + { + // paramLen + // paramName + if (!ADP.IsEmpty(parameterName)) + { + Debug.Assert(parameterName.Length <= 0xff, "parameter name can only be 255 bytes, shouldn't get to TdsParser!"); + int tempLen = parameterName.Length & 0xff; + stateObj.WriteByte((byte)tempLen); + WriteString(parameterName, tempLen, 0, stateObj); + } + else + { + stateObj.WriteByte(0); + } + } + + private static readonly IEnumerable __tvpEmptyValue = new List().AsReadOnly(); + private void WriteSmiParameter(SqlParameter param, int paramIndex, bool sendDefault, TdsParserStateObject stateObj) + { + // + // Determine Metadata + // + ParameterPeekAheadValue peekAhead; + SmiParameterMetaData metaData = param.MetaDataForSmi(out peekAhead); + + if (!_isKatmai) + { + MetaType mt = MetaType.GetMetaTypeFromSqlDbType(metaData.SqlDbType, metaData.IsMultiValued); + throw ADP.VersionDoesNotSupportDataType(mt.TypeName); + } + + // + // Determine value to send + // + object value; + ExtendedClrTypeCode typeCode; + + // if we have an output or default param, set the value to null so we do not send it across to the server + if (sendDefault) + { + // Value for TVP default is empty list, not NULL + if (SqlDbType.Structured == metaData.SqlDbType && metaData.IsMultiValued) + { + value = __tvpEmptyValue; + typeCode = ExtendedClrTypeCode.IEnumerableOfSqlDataRecord; + } + else + { + // Need to send null value for default + value = null; + typeCode = ExtendedClrTypeCode.DBNull; + } + } + else if (param.Direction == ParameterDirection.Output) + { + bool isCLRType = param.ParameterIsSqlType; // We have to forward the TYPE info, we need to know what type we are returning. Once we null the paramater we will no longer be able to distinguish what type were seeing. + param.Value = null; + value = null; + typeCode = ExtendedClrTypeCode.DBNull; + param.ParameterIsSqlType = isCLRType; + } + else + { + value = param.GetCoercedValue(); + typeCode = MetaDataUtilsSmi.DetermineExtendedTypeCodeForUseWithSqlDbType( + metaData.SqlDbType, metaData.IsMultiValued, value, null, SmiContextFactory.KatmaiVersion); + } + + var sendDefaultValue = sendDefault ? 1 : 0; + SqlClientEventSource.Log.AdvancedTraceEvent(" {0}, Sending parameter '{1}', default flag={2}, metadata:{3}", ObjectID, param.ParameterName, sendDefaultValue, metaData.TraceString(3)); + + // + // Write parameter metadata + // + WriteSmiParameterMetaData(metaData, sendDefault, stateObj); + + // + // Now write the value + // + TdsParameterSetter paramSetter = new TdsParameterSetter(stateObj, metaData); + ValueUtilsSmi.SetCompatibleValueV200( + new SmiEventSink_Default(), // TDS Errors/events dealt with at lower level for now, just need an object for processing + paramSetter, + 0, // ordinal. TdsParameterSetter only handles one parameter at a time + metaData, + value, + typeCode, + param.Offset, + 0 < param.Size ? param.Size : -1, + peekAhead); + } + + // Writes metadata portion of parameter stream from an SmiParameterMetaData object. + private void WriteSmiParameterMetaData(SmiParameterMetaData metaData, bool sendDefault, TdsParserStateObject stateObj) + { + // Determine status + byte status = 0; + if (ParameterDirection.Output == metaData.Direction || ParameterDirection.InputOutput == metaData.Direction) + { + status |= TdsEnums.RPC_PARAM_BYREF; + } + + if (sendDefault) + { + status |= TdsEnums.RPC_PARAM_DEFAULT; + } + + // Write everything out + WriteParameterName(metaData.Name, stateObj); + stateObj.WriteByte(status); + WriteSmiTypeInfo(metaData, stateObj); + } + + // Write a TypeInfo stream + // Devnote: we remap the legacy types (text, ntext, and image) to SQLBIGVARCHAR, SQLNVARCHAR, and SQLBIGVARBINARY + private void WriteSmiTypeInfo(SmiExtendedMetaData metaData, TdsParserStateObject stateObj) + { + switch (metaData.SqlDbType) + { + case SqlDbType.BigInt: + stateObj.WriteByte(TdsEnums.SQLINTN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.Binary: + stateObj.WriteByte(TdsEnums.SQLBIGBINARY); + WriteUnsignedShort(checked((ushort)metaData.MaxLength), stateObj); + break; + case SqlDbType.Bit: + stateObj.WriteByte(TdsEnums.SQLBITN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.Char: + stateObj.WriteByte(TdsEnums.SQLBIGCHAR); + WriteUnsignedShort(checked((ushort)(metaData.MaxLength)), stateObj); + WriteUnsignedInt(_defaultCollation.info, stateObj); // TODO: Use metadata's collation?? + stateObj.WriteByte(_defaultCollation.sortId); + break; + case SqlDbType.DateTime: + stateObj.WriteByte(TdsEnums.SQLDATETIMN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.Decimal: + stateObj.WriteByte(TdsEnums.SQLNUMERICN); + stateObj.WriteByte(checked((byte)MetaType.MetaDecimal.FixedLength)); // SmiMetaData's length and actual wire format's length are different + stateObj.WriteByte(0 == metaData.Precision ? (byte)1 : metaData.Precision); + stateObj.WriteByte(metaData.Scale); + break; + case SqlDbType.Float: + stateObj.WriteByte(TdsEnums.SQLFLTN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.Image: + stateObj.WriteByte(TdsEnums.SQLBIGVARBINARY); + WriteUnsignedShort(unchecked((ushort)SmiMetaData.UnlimitedMaxLengthIndicator), stateObj); + break; + case SqlDbType.Int: + stateObj.WriteByte(TdsEnums.SQLINTN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.Money: + stateObj.WriteByte(TdsEnums.SQLMONEYN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.NChar: + stateObj.WriteByte(TdsEnums.SQLNCHAR); + WriteUnsignedShort(checked((ushort)(metaData.MaxLength * 2)), stateObj); + WriteUnsignedInt(_defaultCollation.info, stateObj); // TODO: Use metadata's collation?? + stateObj.WriteByte(_defaultCollation.sortId); + break; + case SqlDbType.NText: + stateObj.WriteByte(TdsEnums.SQLNVARCHAR); + WriteUnsignedShort(unchecked((ushort)SmiMetaData.UnlimitedMaxLengthIndicator), stateObj); + WriteUnsignedInt(_defaultCollation.info, stateObj); // TODO: Use metadata's collation?? + stateObj.WriteByte(_defaultCollation.sortId); + break; + case SqlDbType.NVarChar: + stateObj.WriteByte(TdsEnums.SQLNVARCHAR); + if (SmiMetaData.UnlimitedMaxLengthIndicator == metaData.MaxLength) + { + WriteUnsignedShort(unchecked((ushort)SmiMetaData.UnlimitedMaxLengthIndicator), stateObj); + } + else + { + WriteUnsignedShort(checked((ushort)(metaData.MaxLength * 2)), stateObj); + } + WriteUnsignedInt(_defaultCollation.info, stateObj); // TODO: Use metadata's collation?? + stateObj.WriteByte(_defaultCollation.sortId); + break; + case SqlDbType.Real: + stateObj.WriteByte(TdsEnums.SQLFLTN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.UniqueIdentifier: + stateObj.WriteByte(TdsEnums.SQLUNIQUEID); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.SmallDateTime: + stateObj.WriteByte(TdsEnums.SQLDATETIMN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.SmallInt: + stateObj.WriteByte(TdsEnums.SQLINTN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.SmallMoney: + stateObj.WriteByte(TdsEnums.SQLMONEYN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.Text: + stateObj.WriteByte(TdsEnums.SQLBIGVARCHAR); + WriteUnsignedShort(unchecked((ushort)SmiMetaData.UnlimitedMaxLengthIndicator), stateObj); + WriteUnsignedInt(_defaultCollation.info, stateObj); // TODO: Use metadata's collation?? + stateObj.WriteByte(_defaultCollation.sortId); + break; + case SqlDbType.Timestamp: + stateObj.WriteByte(TdsEnums.SQLBIGBINARY); + WriteShort(checked((int)metaData.MaxLength), stateObj); + break; + case SqlDbType.TinyInt: + stateObj.WriteByte(TdsEnums.SQLINTN); + stateObj.WriteByte(checked((byte)metaData.MaxLength)); + break; + case SqlDbType.VarBinary: + stateObj.WriteByte(TdsEnums.SQLBIGVARBINARY); + WriteUnsignedShort(unchecked((ushort)metaData.MaxLength), stateObj); + break; + case SqlDbType.VarChar: + stateObj.WriteByte(TdsEnums.SQLBIGVARCHAR); + WriteUnsignedShort(unchecked((ushort)metaData.MaxLength), stateObj); + WriteUnsignedInt(_defaultCollation.info, stateObj); // TODO: Use metadata's collation?? + stateObj.WriteByte(_defaultCollation.sortId); + break; + case SqlDbType.Variant: + stateObj.WriteByte(TdsEnums.SQLVARIANT); + WriteInt(checked((int)metaData.MaxLength), stateObj); + break; + case SqlDbType.Xml: + stateObj.WriteByte(TdsEnums.SQLXMLTYPE); + // Is there a schema + if (ADP.IsEmpty(metaData.TypeSpecificNamePart1) && ADP.IsEmpty(metaData.TypeSpecificNamePart2) && + ADP.IsEmpty(metaData.TypeSpecificNamePart3)) + { + stateObj.WriteByte(0); // schema not present + } + else + { + stateObj.WriteByte(1); // schema present + WriteIdentifier(metaData.TypeSpecificNamePart1, stateObj); + WriteIdentifier(metaData.TypeSpecificNamePart2, stateObj); + WriteIdentifierWithShortLength(metaData.TypeSpecificNamePart3, stateObj); + } + break; + case SqlDbType.Udt: + stateObj.WriteByte(TdsEnums.SQLUDT); + WriteIdentifier(metaData.TypeSpecificNamePart1, stateObj); + WriteIdentifier(metaData.TypeSpecificNamePart2, stateObj); + WriteIdentifier(metaData.TypeSpecificNamePart3, stateObj); + break; + case SqlDbType.Structured: + if (metaData.IsMultiValued) + { + WriteTvpTypeInfo(metaData, stateObj); + } + else + { + Debug.Fail("SUDTs not yet supported."); + } + break; + case SqlDbType.Date: + stateObj.WriteByte(TdsEnums.SQLDATE); + break; + case SqlDbType.Time: + stateObj.WriteByte(TdsEnums.SQLTIME); + stateObj.WriteByte(metaData.Scale); + break; + case SqlDbType.DateTime2: + stateObj.WriteByte(TdsEnums.SQLDATETIME2); + stateObj.WriteByte(metaData.Scale); + break; + case SqlDbType.DateTimeOffset: + stateObj.WriteByte(TdsEnums.SQLDATETIMEOFFSET); + stateObj.WriteByte(metaData.Scale); + break; + default: + Debug.Fail("Unknown SqlDbType should have been caught earlier!"); + break; + } + } + + private void WriteTvpTypeInfo(SmiExtendedMetaData metaData, TdsParserStateObject stateObj) + { + Debug.Assert(SqlDbType.Structured == metaData.SqlDbType && metaData.IsMultiValued, + "Invalid metadata for TVPs. Type=" + metaData.SqlDbType); + // Type token + stateObj.WriteByte((byte)TdsEnums.SQLTABLE); + + // 3-part name (DB, Schema, TypeName) + WriteIdentifier(metaData.TypeSpecificNamePart1, stateObj); + WriteIdentifier(metaData.TypeSpecificNamePart2, stateObj); + WriteIdentifier(metaData.TypeSpecificNamePart3, stateObj); + + // TVP_COLMETADATA + if (0 == metaData.FieldMetaData.Count) + { + WriteUnsignedShort((ushort)TdsEnums.TVP_NOMETADATA_TOKEN, stateObj); + } + else + { + // COUNT of columns + WriteUnsignedShort(checked((ushort)metaData.FieldMetaData.Count), stateObj); + + // TvpColumnMetaData for each column (look for defaults in this loop + SmiDefaultFieldsProperty defaults = (SmiDefaultFieldsProperty)metaData.ExtendedProperties[SmiPropertySelector.DefaultFields]; + for (int i = 0; i < metaData.FieldMetaData.Count; i++) + { + WriteTvpColumnMetaData(metaData.FieldMetaData[i], defaults[i], stateObj); + } + + // optional OrderUnique metadata + WriteTvpOrderUnique(metaData, stateObj); + + } + + // END of optional metadata + stateObj.WriteByte(TdsEnums.TVP_END_TOKEN); + } + + // Write a single TvpColumnMetaData stream to the server + private void WriteTvpColumnMetaData(SmiExtendedMetaData md, bool isDefault, TdsParserStateObject stateObj) + { + // User Type + if (SqlDbType.Timestamp == md.SqlDbType) + { + WriteUnsignedInt(TdsEnums.SQLTIMESTAMP, stateObj); + } + else + { + WriteUnsignedInt(0, stateObj); + } + + // Flags + ushort status = TdsEnums.Nullable; + if (isDefault) + { + status |= TdsEnums.TVP_DEFAULT_COLUMN; + } + WriteUnsignedShort(status, stateObj); + + // Type info + WriteSmiTypeInfo(md, stateObj); + + // Column name + // per spec, "ColName is never sent to server or client for TVP, it is required within a TVP to be zero length." + WriteIdentifier(null, stateObj); + } + + // temporary-results structure used only by WriteTvpOrderUnique + // use class to avoid List's per-struct-instantiated memory costs. + private class TdsOrderUnique + { + internal short ColumnOrdinal; + internal byte Flags; + + internal TdsOrderUnique(short ordinal, byte flags) + { + ColumnOrdinal = ordinal; + Flags = flags; + } + } + + private void WriteTvpOrderUnique(SmiExtendedMetaData metaData, TdsParserStateObject stateObj) + { + // TVP_ORDER_UNIQUE token (uniqueness and sort order) + + // Merge order and unique keys into a single token stream + + SmiOrderProperty orderProperty = (SmiOrderProperty)metaData.ExtendedProperties[SmiPropertySelector.SortOrder]; + SmiUniqueKeyProperty uniqueKeyProperty = (SmiUniqueKeyProperty)metaData.ExtendedProperties[SmiPropertySelector.UniqueKey]; + + // Build list from + List columnList = new List(metaData.FieldMetaData.Count); + for (int i = 0; i < metaData.FieldMetaData.Count; i++) + { + + // Add appropriate SortOrder flag + byte flags = 0; + SmiOrderProperty.SmiColumnOrder columnOrder = orderProperty[i]; + if (SortOrder.Ascending == columnOrder.Order) + { + flags = TdsEnums.TVP_ORDERASC_FLAG; + } + else if (SortOrder.Descending == columnOrder.Order) + { + flags = TdsEnums.TVP_ORDERDESC_FLAG; + } + + // Add unique key flage if appropriate + if (uniqueKeyProperty[i]) + { + flags |= TdsEnums.TVP_UNIQUE_FLAG; + } + + // Remember this column if any flags were set + if (0 != flags) + { + columnList.Add(new TdsOrderUnique(checked((short)(i + 1)), flags)); + } + } + + // Write flagged columns to wire... + if (0 < columnList.Count) + { + stateObj.WriteByte(TdsEnums.TVP_ORDER_UNIQUE_TOKEN); + WriteShort(columnList.Count, stateObj); + foreach (TdsOrderUnique column in columnList) + { + WriteShort(column.ColumnOrdinal, stateObj); + stateObj.WriteByte(column.Flags); + } + } + } + + internal Task WriteBulkCopyDone(TdsParserStateObject stateObj) + { + // Write DONE packet + // + if (!(State == TdsParserState.OpenNotLoggedIn || State == TdsParserState.OpenLoggedIn)) + { + throw ADP.ClosedConnectionError(); + } + stateObj.WriteByte(TdsEnums.SQLDONE); + WriteShort(0, stateObj); + WriteShort(0, stateObj); + WriteInt(0, stateObj); + + stateObj._pendingData = true; + stateObj._messageStatus = 0; + return stateObj.WritePacket(TdsEnums.HARDFLUSH); + } + + /// + /// Loads the column encryptions keys into cache. This will read the master key info, + /// decrypt the CEK and keep it ready for encryption. + /// + /// + internal void LoadColumnEncryptionKeys(_SqlMetaDataSet metadataCollection, string serverName) + { + if (_serverSupportsColumnEncryption && ShouldEncryptValuesForBulkCopy()) + { + for (int col = 0; col < metadataCollection.Length; col++) + { + if (null != metadataCollection[col]) + { + _SqlMetaData md = metadataCollection[col]; + if (md.isEncrypted) + { + SqlSecurityUtility.DecryptSymmetricKey(md.cipherMD, serverName); + } + } + } + } + } + + /// + /// Writes a single entry of CEK Table into TDS Stream (for bulk copy). + /// + /// + internal void WriteEncryptionEntries(ref SqlTceCipherInfoTable cekTable, TdsParserStateObject stateObj) + { + for (int i = 0; i < cekTable.Size; i++) + { + // Write Db ID + WriteInt(cekTable[i].DatabaseId, stateObj); + + // Write Key ID + WriteInt(cekTable[i].CekId, stateObj); + + // Write Key Version + WriteInt(cekTable[i].CekVersion, stateObj); + + // Write 8 bytes of key MD Version + Debug.Assert(8 == cekTable[i].CekMdVersion.Length); + stateObj.WriteByteArray(cekTable[i].CekMdVersion, 8, 0); + + // We don't really need to send the keys + stateObj.WriteByte(0x00); + } + } + + /// + /// Writes a CEK Table (as part of COLMETADATA token) for bulk copy. + /// + /// + internal void WriteCekTable(_SqlMetaDataSet metadataCollection, TdsParserStateObject stateObj) + { + if (!_serverSupportsColumnEncryption) + { + return; + } + + // If no cek table is present, send a count of 0 for table size + // Note- Cek table (with 0 entries) will be present if TCE + // was enabled and server supports it! + // OR if encryption was disabled in connection options + if (!metadataCollection.cekTable.HasValue || + !ShouldEncryptValuesForBulkCopy()) + { + WriteShort(0x00, stateObj); + return; + } + + SqlTceCipherInfoTable cekTable = metadataCollection.cekTable.Value; + ushort count = (ushort)cekTable.Size; + + WriteShort(count, stateObj); + + WriteEncryptionEntries(ref cekTable, stateObj); + } + + /// + /// Writes the UserType and TYPE_INFO values for CryptoMetadata (for bulk copy). + /// + /// + internal void WriteTceUserTypeAndTypeInfo(SqlMetaDataPriv mdPriv, TdsParserStateObject stateObj) + { + // Write the UserType (4 byte value) + WriteInt(0x0, stateObj); // TODO: fix this- timestamp columns have 0x50 value here + + Debug.Assert(SqlDbType.Xml != mdPriv.type); + Debug.Assert(SqlDbType.Udt != mdPriv.type); + + stateObj.WriteByte(mdPriv.tdsType); + + switch (mdPriv.type) + { + case SqlDbType.Decimal: + WriteTokenLength(mdPriv.tdsType, mdPriv.length, stateObj); + stateObj.WriteByte(mdPriv.precision); + stateObj.WriteByte(mdPriv.scale); + break; + case SqlDbType.Date: + // Nothing more to write! + break; + case SqlDbType.Time: + case SqlDbType.DateTime2: + case SqlDbType.DateTimeOffset: + stateObj.WriteByte(mdPriv.scale); + break; + default: + WriteTokenLength(mdPriv.tdsType, mdPriv.length, stateObj); + if (mdPriv.metaType.IsCharType && _isShiloh) + { + WriteUnsignedInt(mdPriv.collation.info, stateObj); + stateObj.WriteByte(mdPriv.collation.sortId); + } + break; + } + } + + /// + /// Writes the crypto metadata (as part of COLMETADATA token) for encrypted columns. + /// + /// + internal void WriteCryptoMetadata(_SqlMetaData md, TdsParserStateObject stateObj) + { + if (!_serverSupportsColumnEncryption || // TCE Feature supported + !md.isEncrypted || // Column is not encrypted + !ShouldEncryptValuesForBulkCopy()) + { // TCE disabled on connection string + return; + } + + // Write the ordinal + WriteShort(md.cipherMD.CekTableOrdinal, stateObj); + + // Write UserType and TYPEINFO + WriteTceUserTypeAndTypeInfo(md.baseTI, stateObj); + + // Write Encryption Algo + stateObj.WriteByte(md.cipherMD.CipherAlgorithmId); + + if (TdsEnums.CustomCipherAlgorithmId == md.cipherMD.CipherAlgorithmId) + { + // Write the algorithm name + Debug.Assert(md.cipherMD.CipherAlgorithmName.Length < 256); + stateObj.WriteByte((byte)md.cipherMD.CipherAlgorithmName.Length); + WriteString(md.cipherMD.CipherAlgorithmName, stateObj); + } + + // Write Encryption Algo Type + stateObj.WriteByte(md.cipherMD.EncryptionType); + + // Write Normalization Version + stateObj.WriteByte(md.cipherMD.NormalizationRuleVersion); + } + + internal void WriteBulkCopyMetaData(_SqlMetaDataSet metadataCollection, int count, TdsParserStateObject stateObj) + { + if (!(State == TdsParserState.OpenNotLoggedIn || State == TdsParserState.OpenLoggedIn)) + { + throw ADP.ClosedConnectionError(); + } + + stateObj.WriteByte(TdsEnums.SQLCOLMETADATA); + WriteShort(count, stateObj); + + // Write CEK table - 0 count + WriteCekTable(metadataCollection, stateObj); + + for (int i = 0; i < metadataCollection.Length; i++) + { + if (metadataCollection[i] != null) + { + _SqlMetaData md = metadataCollection[i]; + + // read user type - 4 bytes Yukon, 2 backwards + if (IsYukonOrNewer) + { + WriteInt(0x0, stateObj); + } + else + { + WriteShort(0x0000, stateObj); + } + + // Write the flags + UInt16 flags; + flags = (UInt16)(md.Updatability << 2); + flags |= (UInt16)(md.IsNullable ? (UInt16)TdsEnums.Nullable : (UInt16)0); + flags |= (UInt16)(md.IsIdentity ? (UInt16)TdsEnums.Identity : (UInt16)0); + + // Write the next byte of flags + if (_serverSupportsColumnEncryption) + { // TCE Supported + if (ShouldEncryptValuesForBulkCopy()) + { // TCE enabled on connection options + flags |= (UInt16)(md.isEncrypted ? (UInt16)(TdsEnums.IsEncrypted << 8) : (UInt16)0); + } + } + + WriteShort(flags, stateObj);// write the flags + + // todo: + // for xml WriteTokenLength results in a no-op + // discuss ... + // xml datatype does not have token length in its metadata. So it should be a noop. + + switch (md.type) + { + case SqlDbType.Decimal: + stateObj.WriteByte(md.tdsType); + WriteTokenLength(md.tdsType, md.length, stateObj); + stateObj.WriteByte(md.precision); + stateObj.WriteByte(md.scale); + break; + case SqlDbType.Xml: + // TODO: This doesn't look right. Needs fixing. + stateObj.WriteByteArray(s_xmlMetadataSubstituteSequence, s_xmlMetadataSubstituteSequence.Length, 0); + break; + case SqlDbType.Udt: + stateObj.WriteByte(TdsEnums.SQLBIGVARBINARY); + WriteTokenLength(TdsEnums.SQLBIGVARBINARY, md.length, stateObj); + break; + case SqlDbType.Date: + stateObj.WriteByte(md.tdsType); + break; + case SqlDbType.Time: + case SqlDbType.DateTime2: + case SqlDbType.DateTimeOffset: + stateObj.WriteByte(md.tdsType); + stateObj.WriteByte(md.scale); + break; + default: + stateObj.WriteByte(md.tdsType); + WriteTokenLength(md.tdsType, md.length, stateObj); + if (md.metaType.IsCharType && _isShiloh) + { + WriteUnsignedInt(md.collation.info, stateObj); + stateObj.WriteByte(md.collation.sortId); + } + break; + } + + if (md.metaType.IsLong && !md.metaType.IsPlp) + { + WriteShort(md.tableName.Length, stateObj); + WriteString(md.tableName, stateObj); + } + + WriteCryptoMetadata(md, stateObj); + + stateObj.WriteByte((byte)md.column.Length); + WriteString(md.column, stateObj); + } + } // end for loop + } + + /// + /// Determines if a column value should be encrypted when using BulkCopy (based on connectionstring setting). + /// + /// + internal bool ShouldEncryptValuesForBulkCopy() + { + if (null != _connHandler && + null != _connHandler.ConnectionOptions && + SqlConnectionColumnEncryptionSetting.Enabled == _connHandler.ConnectionOptions.ColumnEncryptionSetting) + { + return true; + } + + return false; + } + + /// + /// Encrypts a column value (for SqlBulkCopy) + /// + /// + internal object EncryptColumnValue(object value, SqlMetaDataPriv metadata, string column, TdsParserStateObject stateObj, bool isDataFeed, bool isSqlType) + { + Debug.Assert(_serverSupportsColumnEncryption, "Server doesn't support encryption, yet we received encryption metadata"); + Debug.Assert(ShouldEncryptValuesForBulkCopy(), "Encryption attempted when not requested"); + + if (isDataFeed) + { // can't encrypt a stream column + SQL.StreamNotSupportOnEncryptedColumn(column); + } + + int actualLengthInBytes; + switch (metadata.baseTI.metaType.NullableType) + { + case TdsEnums.SQLBIGBINARY: + case TdsEnums.SQLBIGVARBINARY: + case TdsEnums.SQLIMAGE: + // For some datatypes, engine does truncation before storing the value. (For example, when + // trying to insert a varbinary(7000) into a varbinary(3000) column). Since we encrypt the + // column values, engine has no way to tell the size of the plaintext datatype. Therefore, + // we truncate the values based on target column sizes here before encrypting them. This + // truncation is only needed if we exceed the max column length or if the target column is + // not a blob type (eg. varbinary(max)). The actual work of truncating the column happens + // when we normalize and serialize the data buffers. The serialization routine expects us + // to report the size of data to be copied out (for serialization). If we underreport the + // size, truncation will happen for us! + actualLengthInBytes = (isSqlType) ? ((SqlBinary)value).Length : ((byte[])value).Length; + if (metadata.baseTI.length > 0 && + actualLengthInBytes > metadata.baseTI.length) + { // see comments agove + actualLengthInBytes = metadata.baseTI.length; + } + break; + + case TdsEnums.SQLUNIQUEID: + actualLengthInBytes = GUID_SIZE; // that's a constant for guid + break; + case TdsEnums.SQLBIGCHAR: + case TdsEnums.SQLBIGVARCHAR: + case TdsEnums.SQLTEXT: + if (null == _defaultEncoding) + { + ThrowUnsupportedCollationEncountered(null); // stateObject only when reading + } + + string stringValue = (isSqlType) ? ((SqlString)value).Value : (string)value; + actualLengthInBytes = _defaultEncoding.GetByteCount(stringValue); + + // If the string length is > max length, then use the max length (see comments above) + if (metadata.baseTI.length > 0 && + actualLengthInBytes > metadata.baseTI.length) + { + actualLengthInBytes = metadata.baseTI.length; // this ensure truncation! + } + + break; + case TdsEnums.SQLNCHAR: + case TdsEnums.SQLNVARCHAR: + case TdsEnums.SQLNTEXT: + actualLengthInBytes = ((isSqlType) ? ((SqlString)value).Value.Length : ((string)value).Length) * 2; + + if (metadata.baseTI.length > 0 && + actualLengthInBytes > metadata.baseTI.length) + { // see comments above + actualLengthInBytes = metadata.baseTI.length; + } + + break; + + default: + actualLengthInBytes = metadata.baseTI.length; + break; + } + + byte[] serializedValue; + if (isSqlType) + { + // SqlType + serializedValue = SerializeUnencryptedSqlValue(value, + metadata.baseTI.metaType, + actualLengthInBytes, + offset: 0, + normalizationVersion: metadata.cipherMD.NormalizationRuleVersion, + stateObj: stateObj); + } + else + { + serializedValue = SerializeUnencryptedValue(value, + metadata.baseTI.metaType, + metadata.baseTI.scale, + actualLengthInBytes, + offset: 0, + isDataFeed: isDataFeed, + normalizationVersion: metadata.cipherMD.NormalizationRuleVersion, + stateObj: stateObj); + } + + Debug.Assert(serializedValue != null, "serializedValue should not be null in TdsExecuteRPC."); + return SqlSecurityUtility.EncryptWithKey( + serializedValue, + metadata.cipherMD, + _connHandler.ConnectionOptions.DataSource); + } + + internal Task WriteBulkCopyValue(object value, SqlMetaDataPriv metadata, TdsParserStateObject stateObj, bool isSqlType, bool isDataFeed, bool isNull) + { + Debug.Assert(!isSqlType || value is INullable, "isSqlType is true, but value can not be type cast to an INullable"); + Debug.Assert(!isDataFeed ^ value is DataFeed, "Incorrect value for isDataFeed"); + + Encoding saveEncoding = _defaultEncoding; + SqlCollation saveCollation = _defaultCollation; + int saveCodePage = _defaultCodePage; + int saveLCID = _defaultLCID; + Task resultTask = null; + Task internalWriteTask = null; + + if (!(State == TdsParserState.OpenNotLoggedIn || State == TdsParserState.OpenLoggedIn)) + { + throw ADP.ClosedConnectionError(); + } + try + { + if (metadata.encoding != null) + { + _defaultEncoding = metadata.encoding; + } + if (metadata.collation != null) + { + // Replace encoding if it is UTF8 + if ((metadata.collation.info & TdsEnums.UTF8_IN_TDSCOLLATION) == TdsEnums.UTF8_IN_TDSCOLLATION) + { + _defaultEncoding = Encoding.UTF8; + } + + _defaultCollation = metadata.collation; + _defaultLCID = _defaultCollation.LCID; + } + _defaultCodePage = metadata.codePage; + + MetaType metatype = metadata.metaType; + int ccb = 0; + int ccbStringBytes = 0; + + if (isNull) + { + // For UDT, remember we treat as binary even though it is a PLP + if (metatype.IsPlp && (metatype.NullableType != TdsEnums.SQLUDT || metatype.IsLong)) + { + WriteLong(unchecked((long)TdsEnums.SQL_PLP_NULL), stateObj); + } + else if (!metatype.IsFixed && !metatype.IsLong && !metatype.IsVarTime) + { + WriteShort(TdsEnums.VARNULL, stateObj); + } + else + { + stateObj.WriteByte(TdsEnums.FIXEDNULL); + } + return resultTask; + } + + if (!isDataFeed) + { + switch (metatype.NullableType) + { + case TdsEnums.SQLBIGBINARY: + case TdsEnums.SQLBIGVARBINARY: + case TdsEnums.SQLIMAGE: + case TdsEnums.SQLUDT: + ccb = (isSqlType) ? ((SqlBinary)value).Length : ((byte[])value).Length; + break; + case TdsEnums.SQLUNIQUEID: + ccb = GUID_SIZE; // that's a constant for guid + break; + case TdsEnums.SQLBIGCHAR: + case TdsEnums.SQLBIGVARCHAR: + case TdsEnums.SQLTEXT: + if (null == _defaultEncoding) + { + ThrowUnsupportedCollationEncountered(null); // stateObject only when reading + } + + string stringValue = null; + if (isSqlType) + { + stringValue = ((SqlString)value).Value; + } + else + { + stringValue = (string)value; + } + + ccb = stringValue.Length; + ccbStringBytes = _defaultEncoding.GetByteCount(stringValue); + break; + case TdsEnums.SQLNCHAR: + case TdsEnums.SQLNVARCHAR: + case TdsEnums.SQLNTEXT: + ccb = ((isSqlType) ? ((SqlString)value).Value.Length : ((string)value).Length) * 2; + break; + case TdsEnums.SQLXMLTYPE: + // Value here could be string or XmlReader + if (value is XmlReader) + { + value = MetaType.GetStringFromXml((XmlReader)value); + } + ccb = ((isSqlType) ? ((SqlString)value).Value.Length : ((string)value).Length) * 2; + break; + + default: + ccb = metadata.length; + break; + } + } + else + { + Debug.Assert(metatype.IsLong && + ((metatype.SqlDbType == SqlDbType.VarBinary && value is StreamDataFeed) || + ((metatype.SqlDbType == SqlDbType.VarChar || metatype.SqlDbType == SqlDbType.NVarChar) && value is TextDataFeed) || + (metatype.SqlDbType == SqlDbType.Xml && value is XmlDataFeed)), + "Stream data feed should only be assigned to VarBinary(max), Text data feed should only be assigned to [N]VarChar(max), Xml data feed should only be assigned to XML(max)"); + } + + + // Expected the text length in data stream for bulk copy of text, ntext, or image data. + // + if (metatype.IsLong) + { + switch (metatype.SqlDbType) + { + case SqlDbType.Text: + case SqlDbType.NText: + case SqlDbType.Image: + stateObj.WriteByteArray(s_longDataHeader, s_longDataHeader.Length, 0); + WriteTokenLength(metadata.tdsType, ccbStringBytes == 0 ? ccb : ccbStringBytes, stateObj); + break; + + case SqlDbType.VarChar: + case SqlDbType.NVarChar: + case SqlDbType.VarBinary: + case SqlDbType.Xml: + case SqlDbType.Udt: + // plp data + WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, stateObj); + break; + } + } + else + { + WriteTokenLength(metadata.tdsType, ccbStringBytes == 0 ? ccb : ccbStringBytes, stateObj); + } + + if (isSqlType) + { + internalWriteTask = WriteSqlValue(value, metatype, ccb, ccbStringBytes, 0, stateObj); + } + else if (metatype.SqlDbType != SqlDbType.Udt || metatype.IsLong) + { + internalWriteTask = WriteValue(value, metatype, metadata.scale, ccb, ccbStringBytes, 0, stateObj, metadata.length, isDataFeed); + if ((internalWriteTask == null) && (_asyncWrite)) + { + internalWriteTask = stateObj.WaitForAccumulatedWrites(); + } + Debug.Assert(_asyncWrite || stateObj.WaitForAccumulatedWrites() == null, "Should not have accumulated writes when writing sync"); + } + else + { + WriteShort(ccb, stateObj); + internalWriteTask = stateObj.WriteByteArray((byte[])value, ccb, 0); + } + +#if DEBUG + //In DEBUG mode, when SetAlwaysTaskOnWrite is true, we create a task. Allows us to verify async execution paths. + if (_asyncWrite && internalWriteTask == null && SqlBulkCopy.SetAlwaysTaskOnWrite == true) + { + internalWriteTask = Task.FromResult(null); + } +#endif + if (internalWriteTask != null) + { //i.e. the write was async. + resultTask = WriteBulkCopyValueSetupContinuation(internalWriteTask, saveEncoding, saveCollation, saveCodePage, saveLCID); + } + } + finally + { + if (internalWriteTask == null) + { + _defaultEncoding = saveEncoding; + _defaultCollation = saveCollation; + _defaultCodePage = saveCodePage; + _defaultLCID = saveLCID; + } + } + return resultTask; + } + + // This is in its own method to avoid always allocating the lambda in WriteBulkCopyValue + private Task WriteBulkCopyValueSetupContinuation(Task internalWriteTask, Encoding saveEncoding, SqlCollation saveCollation, int saveCodePage, int saveLCID) + { + return internalWriteTask.ContinueWith(t => + { + _defaultEncoding = saveEncoding; + _defaultCollation = saveCollation; + _defaultCodePage = saveCodePage; + _defaultLCID = saveLCID; + return t; + }, TaskScheduler.Default).Unwrap(); + } + + // Write mars header data, not including the mars header length + private void WriteMarsHeaderData(TdsParserStateObject stateObj, SqlInternalTransaction transaction) + { + // Function to send over additional payload header data for Yukon and beyond only. + Debug.Assert(_isYukon, "WriteMarsHeaderData called on a non-Yukon server"); + + // These are not necessary - can have local started in distributed. + // Debug.Assert(!(null != sqlTransaction && null != distributedTransaction), "Error to have local (api started) and distributed transaction at the same time!"); + // Debug.Assert(!(null != _userStartedLocalTransaction && null != distributedTransaction), "Error to have local (started outside of the api) and distributed transaction at the same time!"); + + // We may need to update the mars header length if mars header is changed in the future + + WriteShort(TdsEnums.HEADERTYPE_MARS, stateObj); + + if (null != transaction && SqlInternalTransaction.NullTransactionId != transaction.TransactionId) + { + WriteLong(transaction.TransactionId, stateObj); + WriteInt(stateObj.IncrementAndObtainOpenResultCount(transaction), stateObj); + } + else + { + // If no transaction, send over retained transaction descriptor (empty if none retained) + // and always 1 for result count. + WriteLong(_retainedTransactionId, stateObj); + WriteInt(stateObj.IncrementAndObtainOpenResultCount(null), stateObj); + } + } + + private int GetNotificationHeaderSize(SqlNotificationRequest notificationRequest) + { + if (null != notificationRequest) + { + string callbackId = notificationRequest.UserData; + string service = notificationRequest.Options; + int timeout = notificationRequest.Timeout; + + if (null == callbackId) + { + throw ADP.ArgumentNull("CallbackId"); + } + else if (UInt16.MaxValue < callbackId.Length) + { + throw ADP.ArgumentOutOfRange("CallbackId"); + } + + if (null == service) + { + throw ADP.ArgumentNull("Service"); + } + else if (UInt16.MaxValue < service.Length) + { + throw ADP.ArgumentOutOfRange("Service"); + } + + if (-1 > timeout) + { + throw ADP.ArgumentOutOfRange("Timeout"); + } + + // Header Length (uint) (included in size) (already written to output buffer) + // Header Type (ushort) + // NotifyID Length (ushort) + // NotifyID UnicodeStream (unicode text) + // SSBDeployment Length (ushort) + // SSBDeployment UnicodeStream (unicode text) + // Timeout (uint) -- optional + // WEBDATA 102263: Don't send timeout value if it is 0 + + int headerLength = 4 + 2 + 2 + (callbackId.Length * 2) + 2 + (service.Length * 2); + if (timeout > 0) + headerLength += 4; + return headerLength; + } + else + { + return 0; + } + } + + // Write query notificaiton header data, not including the notificaiton header length + private void WriteQueryNotificationHeaderData(SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj) + { + Debug.Assert(_isYukon, "WriteQueryNotificationHeaderData called on a non-Yukon server"); + + // We may need to update the notification header length if the header is changed in the future + + Debug.Assert(null != notificationRequest, "notificaitonRequest is null"); + + string callbackId = notificationRequest.UserData; + string service = notificationRequest.Options; + int timeout = notificationRequest.Timeout; + + // we did verification in GetNotificationHeaderSize, so just assert here. + Debug.Assert(null != callbackId, "CallbackId is null"); + Debug.Assert(UInt16.MaxValue >= callbackId.Length, "CallbackId length is out of range"); + Debug.Assert(null != service, "Service is null"); + Debug.Assert(UInt16.MaxValue >= service.Length, "Service length is out of range"); + Debug.Assert(-1 <= timeout, "Timeout"); + + + SqlClientEventSource.Log.NotificationTraceEvent(" NotificationRequest: userData: '{0}', options: '{1}', timeout: '{2}'", notificationRequest.UserData, notificationRequest.Options, notificationRequest.Timeout); + + WriteShort(TdsEnums.HEADERTYPE_QNOTIFICATION, stateObj); // Query notifications Type + + WriteShort(callbackId.Length * 2, stateObj); // Length in bytes + WriteString(callbackId, stateObj); + + WriteShort(service.Length * 2, stateObj); // Length in bytes + WriteString(service, stateObj); + if (timeout > 0) + WriteInt(timeout, stateObj); + } + + // Write the trace header data, not including the trace header length + private void WriteTraceHeaderData(TdsParserStateObject stateObj) + { + Debug.Assert(this.IncludeTraceHeader, "WriteTraceHeaderData can only be called on a Denali or higher version server and bid trace with the control bit are on"); + + // We may need to update the trace header length if trace header is changed in the future + + ActivityCorrelator.ActivityId actId = ActivityCorrelator.Current; + + WriteShort(TdsEnums.HEADERTYPE_TRACE, stateObj); // Trace Header Type + + stateObj.WriteByteArray(actId.Id.ToByteArray(), GUID_SIZE, 0); // Id (Guid) + WriteUnsignedInt(actId.Sequence, stateObj); // sequence number + + SqlClientEventSource.Log.TraceEvent(" ActivityID {0}", actId); + } + + private void WriteRPCBatchHeaders(TdsParserStateObject stateObj, SqlNotificationRequest notificationRequest) + { + Debug.Assert(_isYukon, "WriteRPCBatchHeaders can only be called on Yukon or higher version servers"); + + /* Header: + TotalLength - DWORD - including all headers and lengths, including itself + Each Data Session: + { + HeaderLength - DWORD - including all header length fields, including itself + HeaderType - USHORT + HeaderData + } + */ + + int notificationHeaderSize = GetNotificationHeaderSize(notificationRequest); + + const int marsHeaderSize = 18; // 4 + 2 + 8 + 4 + + // Header Length (DWORD) + // Header Type (ushort) + // Trace Data Guid + // Trace Data Sequence Number (uint) + const int traceHeaderSize = 26; // 4 + 2 + GUID_SIZE + sizeof(UInt32); + + // TotalLength - DWORD - including all headers and lengths, including itself + int totalHeaderLength = this.IncludeTraceHeader ? (4 + marsHeaderSize + notificationHeaderSize + traceHeaderSize) : (4 + marsHeaderSize + notificationHeaderSize); + Debug.Assert(stateObj._outBytesUsed == stateObj._outputHeaderLen, "Output bytes written before total header length"); + // Write total header length + WriteInt(totalHeaderLength, stateObj); + + // Write Mars header length + WriteInt(marsHeaderSize, stateObj); + // Write Mars header data + WriteMarsHeaderData(stateObj, CurrentTransaction); + + if (0 != notificationHeaderSize) + { + // Write Notification header length + WriteInt(notificationHeaderSize, stateObj); + // Write notificaiton header data + WriteQueryNotificationHeaderData(notificationRequest, stateObj); + } + + if (IncludeTraceHeader) + { + + // Write trace header length + WriteInt(traceHeaderSize, stateObj); + // Write trace header data + WriteTraceHeaderData(stateObj); + } + } + + + // + // Reverse function of GetTokenLength + // + private void WriteTokenLength(byte token, int length, TdsParserStateObject stateObj) + { + int tokenLength = 0; + + Debug.Assert(token != 0, "0 length token!"); + + // For Plp fields, this should only be used when writing to metadata header. + // For actual data length, WriteDataLength should be used. + // For Xml fields, there is no token length field. For MAX fields it is 0xffff. + if (_isYukon) + { // Handle Yukon specific exceptions + if (TdsEnums.SQLUDT == token) + { + tokenLength = 8; + } + else if (token == TdsEnums.SQLXMLTYPE) + { + tokenLength = 8; + } + } + + if (tokenLength == 0) + { + switch (token & TdsEnums.SQLLenMask) + { + case TdsEnums.SQLFixedLen: + Debug.Assert(length == 0x01 << ((token & 0x0c) >> 2), "length does not match encoded length in token"); + tokenLength = 0; + break; + + case TdsEnums.SQLZeroLen: + tokenLength = 0; + break; + + case TdsEnums.SQLVarLen: + case TdsEnums.SQLVarCnt: + if (0 != (token & 0x80)) + tokenLength = 2; + else if (0 == (token & 0x0c)) + + // UNDONE: This should be uint + tokenLength = 4; + else + tokenLength = 1; + + break; + + default: + Debug.Fail("Unknown token length!"); + break; + } + + switch (tokenLength) + { + case 1: + stateObj.WriteByte((byte)length); + break; + + case 2: + WriteShort(length, stateObj); + break; + + case 4: + WriteInt(length, stateObj); + break; + + case 8: + // In the metadata case we write 0xffff for partial length prefixed types. + // For actual data length preceding data, WriteDataLength should be used. + WriteShort(TdsEnums.SQL_USHORTVARMAXLEN, stateObj); + break; + } // end switch + } + } + + // Returns true if BOM byte mark is needed for an XML value + private bool IsBOMNeeded(MetaType type, object value) + { + if (type.NullableType == TdsEnums.SQLXMLTYPE) + { + Type currentType = value.GetType(); + + if (currentType == typeof(SqlString)) + { + if (!((SqlString)value).IsNull && ((((SqlString)value).Value).Length > 0)) + { + if ((((SqlString)value).Value[0] & 0xff) != 0xff) + return true; + } + } + else if ((currentType == typeof(String)) && (((String)value).Length > 0)) + { + if ((value != null) && (((String)value)[0] & 0xff) != 0xff) + return true; + } + else if (currentType == typeof(SqlXml)) + { + if (!((SqlXml)value).IsNull) + return true; + } + else if (currentType == typeof(XmlDataFeed)) + { + return true; // Values will eventually converted to unicode string here + } + } + return false; + } + + private Task GetTerminationTask(Task unterminatedWriteTask, object value, MetaType type, int actualLength, TdsParserStateObject stateObj, bool isDataFeed) + { + if (type.IsPlp && ((actualLength > 0) || isDataFeed)) + { + if (unterminatedWriteTask == null) + { + WriteInt(0, stateObj); + return null; + } + else + { + return AsyncHelper.CreateContinuationTask(unterminatedWriteTask, + WriteInt, 0, stateObj, + connectionToDoom: _connHandler); + } + } + else + { + return unterminatedWriteTask; + } + } + + + private Task WriteSqlValue(object value, MetaType type, int actualLength, int codePageByteSize, int offset, TdsParserStateObject stateObj) + { + return GetTerminationTask( + WriteUnterminatedSqlValue(value, type, actualLength, codePageByteSize, offset, stateObj), + value, type, actualLength, stateObj, false); + } + + // For MAX types, this method can only write everything in one big chunk. If multiple + // chunk writes needed, please use WritePlpBytes/WritePlpChars + private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLength, int codePageByteSize, int offset, TdsParserStateObject stateObj) + { + Debug.Assert(((type.NullableType == TdsEnums.SQLXMLTYPE) || + (value is INullable && !((INullable)value).IsNull)), + "unexpected null SqlType!"); + + // parameters are always sent over as BIG or N types + switch (type.NullableType) + { + case TdsEnums.SQLFLTN: + if (type.FixedLength == 4) + WriteFloat(((SqlSingle)value).Value, stateObj); + else + { + Debug.Assert(type.FixedLength == 8, "Invalid length for SqlDouble type!"); + WriteDouble(((SqlDouble)value).Value, stateObj); + } + + break; + + case TdsEnums.SQLBIGBINARY: + case TdsEnums.SQLBIGVARBINARY: + case TdsEnums.SQLIMAGE: + { + if (type.IsPlp) + { + WriteInt(actualLength, stateObj); // chunk length + } + + if (value is SqlBinary) + { + return stateObj.WriteByteArray(((SqlBinary)value).Value, actualLength, offset, canAccumulate: false); + } + else + { + Debug.Assert(value is SqlBytes); + return stateObj.WriteByteArray(((SqlBytes)value).Value, actualLength, offset, canAccumulate: false); + } + } + + case TdsEnums.SQLUNIQUEID: + { + byte[] b = ((SqlGuid)value).ToByteArray(); + + Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); + stateObj.WriteByteArray(b, actualLength, 0); + break; + } + + case TdsEnums.SQLBITN: + { + Debug.Assert(type.FixedLength == 1, "Invalid length for SqlBoolean type"); + if (((SqlBoolean)value).Value == true) + stateObj.WriteByte(1); + else + stateObj.WriteByte(0); + + break; + } + + case TdsEnums.SQLINTN: + if (type.FixedLength == 1) + stateObj.WriteByte(((SqlByte)value).Value); + else + if (type.FixedLength == 2) + WriteShort(((SqlInt16)value).Value, stateObj); + else + if (type.FixedLength == 4) + WriteInt(((SqlInt32)value).Value, stateObj); + else + { + Debug.Assert(type.FixedLength == 8, "invalid length for SqlIntN type: " + type.FixedLength.ToString(CultureInfo.InvariantCulture)); + WriteLong(((SqlInt64)value).Value, stateObj); + } + + break; + + case TdsEnums.SQLBIGCHAR: + case TdsEnums.SQLBIGVARCHAR: + case TdsEnums.SQLTEXT: + if (type.IsPlp) + { + WriteInt(codePageByteSize, stateObj); // chunk length + } + if (value is System.Data.SqlTypes.SqlChars) + { + String sch = new String(((System.Data.SqlTypes.SqlChars)value).Value); + + return WriteEncodingChar(sch, actualLength, offset, _defaultEncoding, stateObj, canAccumulate: false); + } + else + { + Debug.Assert(value is SqlString); + return WriteEncodingChar(((SqlString)value).Value, actualLength, offset, _defaultEncoding, stateObj, canAccumulate: false); + } + + + case TdsEnums.SQLNCHAR: + case TdsEnums.SQLNVARCHAR: + case TdsEnums.SQLNTEXT: + case TdsEnums.SQLXMLTYPE: + + if (type.IsPlp) + { + if (IsBOMNeeded(type, value)) + { + WriteInt(actualLength + 2, stateObj); // chunk length + WriteShort(TdsEnums.XMLUNICODEBOM, stateObj); + } + else + { + WriteInt(actualLength, stateObj); // chunk length + } + } + + // convert to cchars instead of cbytes + // Xml type is already converted to string through GetCoercedValue + if (actualLength != 0) + actualLength >>= 1; + + if (value is System.Data.SqlTypes.SqlChars) + { + return WriteCharArray(((System.Data.SqlTypes.SqlChars)value).Value, actualLength, offset, stateObj, canAccumulate: false); + } + else + { + Debug.Assert(value is SqlString); + return WriteString(((SqlString)value).Value, actualLength, offset, stateObj, canAccumulate: false); + } + + case TdsEnums.SQLNUMERICN: + Debug.Assert(type.FixedLength <= 17, "Decimal length cannot be greater than 17 bytes"); + WriteSqlDecimal((SqlDecimal)value, stateObj); + break; + + case TdsEnums.SQLDATETIMN: + SqlDateTime dt = (SqlDateTime)value; + + if (type.FixedLength == 4) + { + if (0 > dt.DayTicks || dt.DayTicks > UInt16.MaxValue) + throw SQL.SmallDateTimeOverflow(dt.ToString()); + + WriteShort(dt.DayTicks, stateObj); + WriteShort(dt.TimeTicks / SqlDateTime.SQLTicksPerMinute, stateObj); + } + else + { + WriteInt(dt.DayTicks, stateObj); + WriteInt(dt.TimeTicks, stateObj); + } + + break; + + case TdsEnums.SQLMONEYN: + { + WriteSqlMoney((SqlMoney)value, type.FixedLength, stateObj); + break; + } + + case TdsEnums.SQLUDT: + Debug.Assert(false, "Called WriteSqlValue on UDT param.Should have already been handled"); + throw SQL.UDTUnexpectedResult(value.GetType().AssemblyQualifiedName); + + default: + Debug.Fail("Unknown TdsType!" + type.NullableType.ToString("x2", (IFormatProvider)null)); + break; + } // switch + // return point for accumualated writes, note: non-accumulated writes returned from their case statements + return null; + } + + private class TdsOutputStream : Stream + { + TdsParser _parser; + TdsParserStateObject _stateObj; + byte[] _preambleToStrip; + + public TdsOutputStream(TdsParser parser, TdsParserStateObject stateObj, byte[] preambleToStrip) + { + _parser = parser; + _stateObj = stateObj; + _preambleToStrip = preambleToStrip; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override void Flush() + { + // NOOP + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get + { + throw new NotSupportedException(); + } + set + { + throw new NotSupportedException(); + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + private void StripPreamble(byte[] buffer, ref int offset, ref int count) + { + if (_preambleToStrip != null && count >= _preambleToStrip.Length) + { + + for (int idx = 0; idx < _preambleToStrip.Length; idx++) + { + if (_preambleToStrip[idx] != buffer[idx]) + { + _preambleToStrip = null; + return; + } + } + + offset += _preambleToStrip.Length; + count -= _preambleToStrip.Length; + } + _preambleToStrip = null; + } + + public override void Write(byte[] buffer, int offset, int count) + { + Debug.Assert(!_parser._asyncWrite); + ValidateWriteParameters(buffer, offset, count); + + StripPreamble(buffer, ref offset, ref count); + + if (count > 0) + { + _parser.WriteInt(count, _stateObj); // write length of chunk + _stateObj.WriteByteArray(buffer, count, offset); + } + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + Debug.Assert(_parser._asyncWrite); + ValidateWriteParameters(buffer, offset, count); + + StripPreamble(buffer, ref offset, ref count); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + Task task = null; + if (count > 0) + { + _parser.WriteInt(count, _stateObj); // write length of chunk + task = _stateObj.WriteByteArray(buffer, count, offset, canAccumulate: false); + } + if (task == null) + { + return CompletedTask; + } + else + { + return task; + } + } +#if DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (System.OutOfMemoryException) + { + _parser._connHandler.DoomThisConnection(); + throw; + } + catch (System.StackOverflowException) + { + _parser._connHandler.DoomThisConnection(); + throw; + } + catch (System.Threading.ThreadAbortException) + { + _parser._connHandler.DoomThisConnection(); + throw; + } + } + + internal static void ValidateWriteParameters(byte[] buffer, int offset, int count) + { + if (buffer == null) + { + throw ADP.ArgumentNull(ADP.ParameterBuffer); + } + if (offset < 0) + { + throw ADP.ArgumentOutOfRange(ADP.ParameterOffset); + } + if (count < 0) + { + throw ADP.ArgumentOutOfRange(ADP.ParameterCount); + } + try + { + if (checked(offset + count) > buffer.Length) + { + throw ExceptionBuilder.InvalidOffsetLength(); + } + } + catch (OverflowException) + { + // If we've overflowed when adding offset and count, then they never would have fit into buffer anyway + throw ExceptionBuilder.InvalidOffsetLength(); + } + } + + } + + private class ConstrainedTextWriter : TextWriter + { + TextWriter _next; + int _size; + int _written; + + public ConstrainedTextWriter(TextWriter next, int size) + { + _next = next; + _size = size; + _written = 0; + + if (_size < 1) + { + _size = int.MaxValue; + } + } + + public bool IsComplete + { + get + { + return _size > 0 && _written >= _size; + } + } + + public override Encoding Encoding + { + get { return _next.Encoding; } + } + + public override void Flush() + { + _next.Flush(); + } + + public override Task FlushAsync() + { + return _next.FlushAsync(); + } + + public override void Write(char value) + { + if (_written < _size) + { + _next.Write(value); + _written++; + } + Debug.Assert(_size < 0 || _written <= _size, $"Length of data written exceeds specified length. Written: {_written}, specified: {_size}"); + } + + public override void Write(char[] buffer, int index, int count) + { + + ValidateWriteParameters(buffer, index, count); + + Debug.Assert(_size >= _written); + count = Math.Min(_size - _written, count); + if (count > 0) + { + _next.Write(buffer, index, count); + } + _written += count; + } + + public override Task WriteAsync(char value) + { + + if (_written < _size) + { + _written++; + return _next.WriteAsync(value); + } + + return CompletedTask; + } + + public override Task WriteAsync(char[] buffer, int index, int count) + { + + ValidateWriteParameters(buffer, index, count); + + Debug.Assert(_size >= _written); + count = Math.Min(_size - _written, count); + if (count > 0) + { + _written += count; + return _next.WriteAsync(buffer, index, count); + } + + return CompletedTask; + } + + public override Task WriteAsync(string value) + { + return WriteAsync(value.ToCharArray()); + } + + internal static void ValidateWriteParameters(char[] buffer, int offset, int count) + { + if (buffer == null) + { + throw ADP.ArgumentNull(ADP.ParameterBuffer); + } + if (offset < 0) + { + throw ADP.ArgumentOutOfRange(ADP.ParameterOffset); + } + if (count < 0) + { + throw ADP.ArgumentOutOfRange(ADP.ParameterCount); + } + try + { + if (checked(offset + count) > buffer.Length) + { + throw ExceptionBuilder.InvalidOffsetLength(); + } + } + catch (OverflowException) + { + // If we've overflowed when adding offset and count, then they never would have fit into buffer anyway + throw ExceptionBuilder.InvalidOffsetLength(); + } + } + + } + + private async Task WriteXmlFeed(XmlDataFeed feed, TdsParserStateObject stateObj, bool needBom, Encoding encoding, int size) + { + byte[] preambleToSkip = null; + if (!needBom) + { + preambleToSkip = encoding.GetPreamble(); + } + ConstrainedTextWriter writer = new ConstrainedTextWriter(new StreamWriter(new TdsOutputStream(this, stateObj, preambleToSkip), encoding), size); + + XmlWriterSettings writerSettings = new XmlWriterSettings(); + writerSettings.CloseOutput = false; // don't close the memory stream + writerSettings.ConformanceLevel = ConformanceLevel.Fragment; + if (_asyncWrite) + { + writerSettings.Async = true; + } + XmlWriter ww = XmlWriter.Create(writer, writerSettings); + + if (feed._source.ReadState == ReadState.Initial) + { + feed._source.Read(); + } + + while (!feed._source.EOF && !writer.IsComplete) + { + + // We are copying nodes from a reader to a writer. This will cause the + // XmlDeclaration to be emitted despite ConformanceLevel.Fragment above. + // Therefore, we filter out the XmlDeclaration while copying. + if (feed._source.NodeType == XmlNodeType.XmlDeclaration) + { + feed._source.Read(); + continue; + } + + if (_asyncWrite) + { + await ww.WriteNodeAsync(feed._source, true).ConfigureAwait(false); + } + else + { + ww.WriteNode(feed._source, true); + } + } + + if (_asyncWrite) + { + await ww.FlushAsync().ConfigureAwait(false); + } + else + { + ww.Flush(); + } + } + + private async Task WriteTextFeed(TextDataFeed feed, Encoding encoding, bool needBom, TdsParserStateObject stateObj, int size) + { + Debug.Assert(encoding == null || !needBom); + char[] inBuff = new char[constTextBufferSize]; + + encoding = encoding ?? new UnicodeEncoding(false, false); + ConstrainedTextWriter writer = new ConstrainedTextWriter(new StreamWriter(new TdsOutputStream(this, stateObj, null), encoding), size); + + if (needBom) + { + if (_asyncWrite) + { + await writer.WriteAsync((char)TdsEnums.XMLUNICODEBOM).ConfigureAwait(false); + } + else + { + writer.Write((char)TdsEnums.XMLUNICODEBOM); + } + } + + int nWritten = 0; + do + { + int nRead = 0; + + if (_asyncWrite) + { + nRead = await feed._source.ReadBlockAsync(inBuff, 0, constTextBufferSize).ConfigureAwait(false); + } + else + { + nRead = feed._source.ReadBlock(inBuff, 0, constTextBufferSize); + } + + if (nRead == 0) + { + break; + } + + if (_asyncWrite) + { + await writer.WriteAsync(inBuff, 0, nRead).ConfigureAwait(false); + } + else + { + writer.Write(inBuff, 0, nRead); + } + + nWritten += nRead; + } while (!writer.IsComplete); + + if (_asyncWrite) + { + await writer.FlushAsync().ConfigureAwait(false); + } + else + { + writer.Flush(); + } + } + + private async Task WriteStreamFeed(StreamDataFeed feed, TdsParserStateObject stateObj, int len) + { + TdsOutputStream output = new TdsOutputStream(this, stateObj, null); + byte[] buff = new byte[constBinBufferSize]; + int nWritten = 0; + do + { + int nRead = 0; + int readSize = constBinBufferSize; + if (len > 0 && nWritten + readSize > len) + { + readSize = len - nWritten; + } + + Debug.Assert(readSize >= 0); + + if (_asyncWrite) + { + nRead = await feed._source.ReadAsync(buff, 0, readSize).ConfigureAwait(false); + } + else + { + nRead = feed._source.Read(buff, 0, readSize); + } + + if (nRead == 0) + { + return; + } + + if (_asyncWrite) + { + await output.WriteAsync(buff, 0, nRead).ConfigureAwait(false); + } + else + { + output.Write(buff, 0, nRead); + } + + nWritten += nRead; + } while (len <= 0 || nWritten < len); + } + + private Task NullIfCompletedWriteTask(Task task) + { + if (task == null) + { + return null; + } + switch (task.Status) + { + case TaskStatus.RanToCompletion: + return null; + case TaskStatus.Faulted: + throw task.Exception.InnerException; + case TaskStatus.Canceled: + throw SQL.OperationCancelled(); + default: + return task; + } + } + + private Task WriteValue(object value, MetaType type, byte scale, int actualLength, int encodingByteSize, int offset, TdsParserStateObject stateObj, int paramSize, bool isDataFeed) + { + return GetTerminationTask(WriteUnterminatedValue(value, type, scale, actualLength, encodingByteSize, offset, stateObj, paramSize, isDataFeed), + value, type, actualLength, stateObj, isDataFeed); + } + + // For MAX types, this method can only write everything in one big chunk. If multiple + // chunk writes needed, please use WritePlpBytes/WritePlpChars + private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int actualLength, int encodingByteSize, int offset, TdsParserStateObject stateObj, int paramSize, bool isDataFeed) + { + Debug.Assert((null != value) && (DBNull.Value != value), "unexpected missing or empty object"); + + // parameters are always sent over as BIG or N types + switch (type.NullableType) + { + case TdsEnums.SQLFLTN: + if (type.FixedLength == 4) + WriteFloat((Single)value, stateObj); + else + { + Debug.Assert(type.FixedLength == 8, "Invalid length for SqlDouble type!"); + WriteDouble((Double)value, stateObj); + } + + break; + + case TdsEnums.SQLBIGBINARY: + case TdsEnums.SQLBIGVARBINARY: + case TdsEnums.SQLIMAGE: + case TdsEnums.SQLUDT: + { + // An array should be in the object + Debug.Assert(isDataFeed || value is byte[], "Value should be an array of bytes"); + Debug.Assert(!isDataFeed || value is StreamDataFeed, "Value should be a stream"); + + if (isDataFeed) + { + Debug.Assert(type.IsPlp, "Stream assigned to non-PLP was not converted!"); + return NullIfCompletedWriteTask(WriteStreamFeed((StreamDataFeed)value, stateObj, paramSize)); + } + else + { + if (type.IsPlp) + { + WriteInt(actualLength, stateObj); // chunk length + } + + return stateObj.WriteByteArray((byte[])value, actualLength, offset, canAccumulate: false); + } + } + + case TdsEnums.SQLUNIQUEID: + { + System.Guid guid = (System.Guid)value; + byte[] b = guid.ToByteArray(); + + Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); + stateObj.WriteByteArray(b, actualLength, 0); + break; + } + + case TdsEnums.SQLBITN: + { + Debug.Assert(type.FixedLength == 1, "Invalid length for SqlBoolean type"); + if ((bool)value == true) + stateObj.WriteByte(1); + else + stateObj.WriteByte(0); + + break; + } + + case TdsEnums.SQLINTN: + if (type.FixedLength == 1) + stateObj.WriteByte((byte)value); + else if (type.FixedLength == 2) + WriteShort((Int16)value, stateObj); + else if (type.FixedLength == 4) + WriteInt((Int32)value, stateObj); + else + { + Debug.Assert(type.FixedLength == 8, "invalid length for SqlIntN type: " + type.FixedLength.ToString(CultureInfo.InvariantCulture)); + WriteLong((Int64)value, stateObj); + } + + break; + + case TdsEnums.SQLBIGCHAR: + case TdsEnums.SQLBIGVARCHAR: + case TdsEnums.SQLTEXT: + { + Debug.Assert(!isDataFeed || (value is TextDataFeed || value is XmlDataFeed), "Value must be a TextReader or XmlReader"); + Debug.Assert(isDataFeed || (value is string || value is byte[]), "Value is a byte array or string"); + + if (isDataFeed) + { + Debug.Assert(type.IsPlp, "Stream assigned to non-PLP was not converted!"); + TextDataFeed tdf = value as TextDataFeed; + if (tdf == null) + { + return NullIfCompletedWriteTask(WriteXmlFeed((XmlDataFeed)value, stateObj, needBom: true, encoding: _defaultEncoding, size: paramSize)); + } + else + { + return NullIfCompletedWriteTask(WriteTextFeed(tdf, _defaultEncoding, false, stateObj, paramSize)); + } + } + else + { + if (type.IsPlp) + { + WriteInt(encodingByteSize, stateObj); // chunk length + } + if (value is byte[]) + { // If LazyMat non-filled blob, send cookie rather than value + return stateObj.WriteByteArray((byte[])value, actualLength, 0, canAccumulate: false); + } + else + { + return WriteEncodingChar((string)value, actualLength, offset, _defaultEncoding, stateObj, canAccumulate: false); + } + } + } + case TdsEnums.SQLNCHAR: + case TdsEnums.SQLNVARCHAR: + case TdsEnums.SQLNTEXT: + case TdsEnums.SQLXMLTYPE: + { + Debug.Assert(!isDataFeed || (value is TextDataFeed || value is XmlDataFeed), "Value must be a TextReader or XmlReader"); + Debug.Assert(isDataFeed || (value is string || value is byte[]), "Value is a byte array or string"); + + if (isDataFeed) + { + Debug.Assert(type.IsPlp, "Stream assigned to non-PLP was not converted!"); + TextDataFeed tdf = value as TextDataFeed; + if (tdf == null) + { + return NullIfCompletedWriteTask(WriteXmlFeed((XmlDataFeed)value, stateObj, IsBOMNeeded(type, value), Encoding.Unicode, paramSize)); + } + else + { + return NullIfCompletedWriteTask(WriteTextFeed(tdf, null, IsBOMNeeded(type, value), stateObj, paramSize)); + } + } + else + { + if (type.IsPlp) + { + if (IsBOMNeeded(type, value)) + { + WriteInt(actualLength + 2, stateObj); // chunk length + WriteShort(TdsEnums.XMLUNICODEBOM, stateObj); + } + else + { + WriteInt(actualLength, stateObj); // chunk length + } + } + if (value is byte[]) + { // If LazyMat non-filled blob, send cookie rather than value + return stateObj.WriteByteArray((byte[])value, actualLength, 0, canAccumulate: false); + } + else + { + // convert to cchars instead of cbytes + actualLength >>= 1; + return WriteString((string)value, actualLength, offset, stateObj, canAccumulate: false); + } + } + } + case TdsEnums.SQLNUMERICN: + Debug.Assert(type.FixedLength <= 17, "Decimal length cannot be greater than 17 bytes"); + WriteDecimal((Decimal)value, stateObj); + break; + + case TdsEnums.SQLDATETIMN: + Debug.Assert(type.FixedLength <= 0xff, "Invalid Fixed Length"); + + TdsDateTime dt = MetaType.FromDateTime((DateTime)value, (byte)type.FixedLength); + + if (type.FixedLength == 4) + { + if (0 > dt.days || dt.days > UInt16.MaxValue) + throw SQL.SmallDateTimeOverflow(MetaType.ToDateTime(dt.days, dt.time, 4).ToString(CultureInfo.InvariantCulture)); + + WriteShort(dt.days, stateObj); + WriteShort(dt.time, stateObj); + } + else + { + WriteInt(dt.days, stateObj); + WriteInt(dt.time, stateObj); + } + + break; + + case TdsEnums.SQLMONEYN: + { + WriteCurrency((Decimal)value, type.FixedLength, stateObj); + break; + } + + case TdsEnums.SQLDATE: + { + WriteDate((DateTime)value, stateObj); + break; + } + + case TdsEnums.SQLTIME: + if (scale > TdsEnums.DEFAULT_VARTIME_SCALE) + { + throw SQL.TimeScaleValueOutOfRange(scale); + } + WriteTime((TimeSpan)value, scale, actualLength, stateObj); + break; + + case TdsEnums.SQLDATETIME2: + if (scale > TdsEnums.DEFAULT_VARTIME_SCALE) + { + throw SQL.TimeScaleValueOutOfRange(scale); + } + WriteDateTime2((DateTime)value, scale, actualLength, stateObj); + break; + + case TdsEnums.SQLDATETIMEOFFSET: + WriteDateTimeOffset((DateTimeOffset)value, scale, actualLength, stateObj); + break; + + default: + Debug.Fail("Unknown TdsType!" + type.NullableType.ToString("x2", (IFormatProvider)null)); + break; + } // switch + // return point for accumualated writes, note: non-accumulated writes returned from their case statements + return null; + // Debug.WriteLine("value: " + value.ToString(CultureInfo.InvariantCulture)); + } + + /// + /// Write parameter encryption metadata and returns a task if necessary. + /// + private Task WriteEncryptionMetadata(Task terminatedWriteTask, SqlColumnEncryptionInputParameterInfo columnEncryptionParameterInfo, TdsParserStateObject stateObj) + { + Debug.Assert(columnEncryptionParameterInfo != null, @"columnEncryptionParameterInfo cannot be null"); + Debug.Assert(stateObj != null, @"stateObj cannot be null"); + + // If there is not task already, simply write the encryption metadata synchronously. + if (terminatedWriteTask == null) + { + WriteEncryptionMetadata(columnEncryptionParameterInfo, stateObj); + return null; + } + else + { + // Otherwise, create a continuation task to write the encryption metadata after the previous write completes. + return AsyncHelper.CreateContinuationTask(terminatedWriteTask, + WriteEncryptionMetadata, columnEncryptionParameterInfo, stateObj, + connectionToDoom: _connHandler); + } + } + + /// + /// Write parameter encryption metadata. + /// + private void WriteEncryptionMetadata(SqlColumnEncryptionInputParameterInfo columnEncryptionParameterInfo, TdsParserStateObject stateObj) + { + Debug.Assert(columnEncryptionParameterInfo != null, @"columnEncryptionParameterInfo cannot be null"); + Debug.Assert(stateObj != null, @"stateObj cannot be null"); + + // Write the TypeInfo. + WriteSmiTypeInfo(columnEncryptionParameterInfo.ParameterMetadata, stateObj); + + // Write the serialized array in columnEncryptionParameterInfo. + stateObj.WriteByteArray(columnEncryptionParameterInfo.SerializedWireFormat, + columnEncryptionParameterInfo.SerializedWireFormat.Length, + offsetBuffer: 0); + } + + // For MAX types, this method can only write everything in one big chunk. If multiple + // chunk writes needed, please use WritePlpBytes/WritePlpChars + private byte[] SerializeUnencryptedValue(object value, MetaType type, byte scale, int actualLength, int offset, bool isDataFeed, byte normalizationVersion, TdsParserStateObject stateObj) + { + Debug.Assert((null != value) && (DBNull.Value != value), "unexpected missing or empty object"); + + if (normalizationVersion != 0x01) + { + throw SQL.UnsupportedNormalizationVersion(normalizationVersion); + } + + // parameters are always sent over as BIG or N types + switch (type.NullableType) + { + case TdsEnums.SQLFLTN: + if (type.FixedLength == 4) + return SerializeFloat((Single)value); + else + { + Debug.Assert(type.FixedLength == 8, "Invalid length for SqlDouble type!"); + return SerializeDouble((Double)value); + } + + case TdsEnums.SQLBIGBINARY: + case TdsEnums.SQLBIGVARBINARY: + case TdsEnums.SQLIMAGE: + case TdsEnums.SQLUDT: + { + Debug.Assert(!isDataFeed, "We cannot serialize streams"); + Debug.Assert(value is byte[], "Value should be an array of bytes"); + + byte[] b = new byte[actualLength]; + Buffer.BlockCopy((byte[])value, offset, b, 0, actualLength); + return b; + } + + case TdsEnums.SQLUNIQUEID: + { + System.Guid guid = (System.Guid)value; + byte[] b = guid.ToByteArray(); + + Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); + return b; + } + + case TdsEnums.SQLBITN: + { + Debug.Assert(type.FixedLength == 1, "Invalid length for SqlBoolean type"); + + // We normalize to allow conversion across data types. BIT is serialized into a BIGINT. + return SerializeLong((bool)value == true ? 1 : 0, stateObj); + } + + case TdsEnums.SQLINTN: + if (type.FixedLength == 1) + return SerializeLong((byte)value, stateObj); + + if (type.FixedLength == 2) + return SerializeLong((Int16)value, stateObj); + + if (type.FixedLength == 4) + return SerializeLong((Int32)value, stateObj); + + Debug.Assert(type.FixedLength == 8, "invalid length for SqlIntN type: " + type.FixedLength.ToString(CultureInfo.InvariantCulture)); + return SerializeLong((Int64)value, stateObj); + + case TdsEnums.SQLBIGCHAR: + case TdsEnums.SQLBIGVARCHAR: + case TdsEnums.SQLTEXT: + { + Debug.Assert(!isDataFeed, "We cannot serialize streams"); + Debug.Assert((value is string || value is byte[]), "Value is a byte array or string"); + + if (value is byte[]) + { // If LazyMat non-filled blob, send cookie rather than value + byte[] b = new byte[actualLength]; + Buffer.BlockCopy((byte[])value, 0, b, 0, actualLength); + return b; + } + else + { + return SerializeEncodingChar((string)value, actualLength, offset, _defaultEncoding); + } + } + case TdsEnums.SQLNCHAR: + case TdsEnums.SQLNVARCHAR: + case TdsEnums.SQLNTEXT: + case TdsEnums.SQLXMLTYPE: + { + Debug.Assert(!isDataFeed, "We cannot serialize streams"); + Debug.Assert((value is string || value is byte[]), "Value is a byte array or string"); + + if (value is byte[]) + { // If LazyMat non-filled blob, send cookie rather than value + byte[] b = new byte[actualLength]; + Buffer.BlockCopy((byte[])value, 0, b, 0, actualLength); + return b; + } + else + { // convert to cchars instead of cbytes + actualLength >>= 1; + return SerializeString((string)value, actualLength, offset); + } + } + case TdsEnums.SQLNUMERICN: + Debug.Assert(type.FixedLength <= 17, "Decimal length cannot be greater than 17 bytes"); + return SerializeDecimal((Decimal)value, stateObj); + + case TdsEnums.SQLDATETIMN: + Debug.Assert(type.FixedLength <= 0xff, "Invalid Fixed Length"); + + TdsDateTime dt = MetaType.FromDateTime((DateTime)value, (byte)type.FixedLength); + + if (type.FixedLength == 4) + { + if (0 > dt.days || dt.days > UInt16.MaxValue) + throw SQL.SmallDateTimeOverflow(MetaType.ToDateTime(dt.days, dt.time, 4).ToString(CultureInfo.InvariantCulture)); + + if (null == stateObj._bIntBytes) + { + stateObj._bIntBytes = new byte[4]; + } + + byte[] b = stateObj._bIntBytes; + int current = 0; + + byte[] bPart = SerializeShort(dt.days, stateObj); + Buffer.BlockCopy(bPart, 0, b, current, 2); + current += 2; + + bPart = SerializeShort(dt.time, stateObj); + Buffer.BlockCopy(bPart, 0, b, current, 2); + + return b; + } + else + { + if (null == stateObj._bLongBytes) + { + stateObj._bLongBytes = new byte[8]; + } + byte[] b = stateObj._bLongBytes; + int current = 0; + + byte[] bPart = SerializeInt(dt.days, stateObj); + Buffer.BlockCopy(bPart, 0, b, current, 4); + current += 4; + + bPart = SerializeInt(dt.time, stateObj); + Buffer.BlockCopy(bPart, 0, b, current, 4); + + return b; + } + + case TdsEnums.SQLMONEYN: + { + return SerializeCurrency((Decimal)value, type.FixedLength, stateObj); + } + + case TdsEnums.SQLDATE: + { + return SerializeDate((DateTime)value); + } + + case TdsEnums.SQLTIME: + if (scale > TdsEnums.DEFAULT_VARTIME_SCALE) + { + throw SQL.TimeScaleValueOutOfRange(scale); + } + return SerializeTime((TimeSpan)value, scale, actualLength); + + case TdsEnums.SQLDATETIME2: + if (scale > TdsEnums.DEFAULT_VARTIME_SCALE) + { + throw SQL.TimeScaleValueOutOfRange(scale); + } + return SerializeDateTime2((DateTime)value, scale, actualLength); + + case TdsEnums.SQLDATETIMEOFFSET: + if (scale > TdsEnums.DEFAULT_VARTIME_SCALE) + { + throw SQL.TimeScaleValueOutOfRange(scale); + } + return SerializeDateTimeOffset((DateTimeOffset)value, scale, actualLength); + + default: + throw SQL.UnsupportedDatatypeEncryption(type.TypeName); + } // switch + // Debug.WriteLine("value: " + value.ToString(CultureInfo.InvariantCulture)); + } + + // For MAX types, this method can only write everything in one big chunk. If multiple + // chunk writes needed, please use WritePlpBytes/WritePlpChars + private byte[] SerializeUnencryptedSqlValue(object value, MetaType type, int actualLength, int offset, byte normalizationVersion, TdsParserStateObject stateObj) + { + Debug.Assert(((type.NullableType == TdsEnums.SQLXMLTYPE) || + (value is INullable && !((INullable)value).IsNull)), + "unexpected null SqlType!"); + + if (normalizationVersion != 0x01) + { + throw SQL.UnsupportedNormalizationVersion(normalizationVersion); + } + + // parameters are always sent over as BIG or N types + switch (type.NullableType) + { + case TdsEnums.SQLFLTN: + if (type.FixedLength == 4) + return SerializeFloat(((SqlSingle)value).Value); + else + { + Debug.Assert(type.FixedLength == 8, "Invalid length for SqlDouble type!"); + return SerializeDouble(((SqlDouble)value).Value); + } + + case TdsEnums.SQLBIGBINARY: + case TdsEnums.SQLBIGVARBINARY: + case TdsEnums.SQLIMAGE: + { + byte[] b = new byte[actualLength]; + + if (value is SqlBinary) + { + Buffer.BlockCopy(((SqlBinary)value).Value, offset, b, 0, actualLength); + } + else + { + Debug.Assert(value is SqlBytes); + Buffer.BlockCopy(((SqlBytes)value).Value, offset, b, 0, actualLength); + } + return b; + } + + case TdsEnums.SQLUNIQUEID: + { + byte[] b = ((SqlGuid)value).ToByteArray(); + + Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); + return b; + } + + case TdsEnums.SQLBITN: + { + Debug.Assert(type.FixedLength == 1, "Invalid length for SqlBoolean type"); + + // We normalize to allow conversion across data types. BIT is serialized into a BIGINT. + return SerializeLong(((SqlBoolean)value).Value == true ? 1 : 0, stateObj); + } + + case TdsEnums.SQLINTN: + // We normalize to allow conversion across data types. All data types below are serialized into a BIGINT. + if (type.FixedLength == 1) + return SerializeLong(((SqlByte)value).Value, stateObj); + + if (type.FixedLength == 2) + return SerializeLong(((SqlInt16)value).Value, stateObj); + + if (type.FixedLength == 4) + return SerializeLong(((SqlInt32)value).Value, stateObj); + else + { + Debug.Assert(type.FixedLength == 8, "invalid length for SqlIntN type: " + type.FixedLength.ToString(CultureInfo.InvariantCulture)); + return SerializeLong(((SqlInt64)value).Value, stateObj); + } + + case TdsEnums.SQLBIGCHAR: + case TdsEnums.SQLBIGVARCHAR: + case TdsEnums.SQLTEXT: + if (value is System.Data.SqlTypes.SqlChars) + { + String sch = new String(((System.Data.SqlTypes.SqlChars)value).Value); + return SerializeEncodingChar(sch, actualLength, offset, _defaultEncoding); + } + else + { + Debug.Assert(value is SqlString); + return SerializeEncodingChar(((SqlString)value).Value, actualLength, offset, _defaultEncoding); + } + + + case TdsEnums.SQLNCHAR: + case TdsEnums.SQLNVARCHAR: + case TdsEnums.SQLNTEXT: + case TdsEnums.SQLXMLTYPE: + // convert to cchars instead of cbytes + // Xml type is already converted to string through GetCoercedValue + if (actualLength != 0) + actualLength >>= 1; + + if (value is System.Data.SqlTypes.SqlChars) + { + return SerializeCharArray(((System.Data.SqlTypes.SqlChars)value).Value, actualLength, offset); + } + else + { + Debug.Assert(value is SqlString); + return SerializeString(((SqlString)value).Value, actualLength, offset); + } + + case TdsEnums.SQLNUMERICN: + Debug.Assert(type.FixedLength <= 17, "Decimal length cannot be greater than 17 bytes"); + return SerializeSqlDecimal((SqlDecimal)value, stateObj); + + case TdsEnums.SQLDATETIMN: + SqlDateTime dt = (SqlDateTime)value; + + if (type.FixedLength == 4) + { + if (0 > dt.DayTicks || dt.DayTicks > UInt16.MaxValue) + throw SQL.SmallDateTimeOverflow(dt.ToString()); + + if (null == stateObj._bIntBytes) + { + stateObj._bIntBytes = new byte[4]; + } + + byte[] b = stateObj._bIntBytes; + int current = 0; + + byte[] bPart = SerializeShort(dt.DayTicks, stateObj); + Buffer.BlockCopy(bPart, 0, b, current, 2); + current += 2; + + bPart = SerializeShort(dt.TimeTicks / SqlDateTime.SQLTicksPerMinute, stateObj); + Buffer.BlockCopy(bPart, 0, b, current, 2); + + return b; + } + else + { + if (null == stateObj._bLongBytes) + { + stateObj._bLongBytes = new byte[8]; + } + + byte[] b = stateObj._bLongBytes; + int current = 0; + + byte[] bPart = SerializeInt(dt.DayTicks, stateObj); + Buffer.BlockCopy(bPart, 0, b, current, 4); + current += 4; + + bPart = SerializeInt(dt.TimeTicks, stateObj); + Buffer.BlockCopy(bPart, 0, b, current, 4); + + return b; + } + + case TdsEnums.SQLMONEYN: + { + return SerializeSqlMoney((SqlMoney)value, type.FixedLength, stateObj); + } + + default: + throw SQL.UnsupportedDatatypeEncryption(type.TypeName); + } // switch + } + + // + // we always send over nullable types for parameters so we always write the varlen fields + // + + internal void WriteParameterVarLen(MetaType type, int size, bool isNull, TdsParserStateObject stateObj, bool unknownLength = false) + { + if (type.IsLong) + { // text/image/SQLVariant have a 4 byte length, plp datatypes have 8 byte lengths + if (isNull) + { + if (type.IsPlp) + { + WriteLong(unchecked((long)TdsEnums.SQL_PLP_NULL), stateObj); + } + else + { + WriteInt(unchecked((int)TdsEnums.VARLONGNULL), stateObj); + } + } + else if (type.NullableType == TdsEnums.SQLXMLTYPE || unknownLength) + { + WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, stateObj); + } + else if (type.IsPlp) + { + // Non-xml plp types + WriteLong((long)size, stateObj); + } + else + { + WriteInt(size, stateObj); + } + } + else if (type.IsVarTime) + { + if (isNull) + { + stateObj.WriteByte(TdsEnums.FIXEDNULL); + } + else + { + stateObj.WriteByte((byte)size); + } + } + else if (false == type.IsFixed) + { // non-long but variable length column, must be a BIG* type: 2 byte length + if (isNull) + { + WriteShort(TdsEnums.VARNULL, stateObj); + } + else + { + WriteShort(size, stateObj); + } + } + else + { + if (isNull) + { + stateObj.WriteByte(TdsEnums.FIXEDNULL); + } + else + { + Debug.Assert(type.FixedLength <= 0xff, "WriteParameterVarLen: invalid one byte length!"); + stateObj.WriteByte((byte)(type.FixedLength & 0xff)); // 1 byte for everything else + } + } + } + + // Reads the next chunk in a nvarchar(max) data stream. + // This call must be preceeded by a call to ReadPlpLength or ReadDataLength. + // Will not start reading into the next chunk if bytes requested is larger than + // the current chunk length. Do another ReadPlpLength, ReadPlpUnicodeChars in that case. + // Returns the actual chars read + private bool TryReadPlpUnicodeCharsChunk(char[] buff, int offst, int len, TdsParserStateObject stateObj, out int charsRead) + { + + Debug.Assert((buff == null && len == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpUnicodeChars()!"); + Debug.Assert((stateObj._longlen != 0) && (stateObj._longlen != TdsEnums.SQL_PLP_NULL), + "Out of sync plp read request"); + if (stateObj._longlenleft == 0) + { + Debug.Fail("Out of sync read request"); + charsRead = 0; + return true; + } + + charsRead = len; + + // stateObj._longlenleft is in bytes + if ((stateObj._longlenleft >> 1) < (ulong)len) + charsRead = (int)(stateObj._longlenleft >> 1); + + for (int ii = 0; ii < charsRead; ii++) + { + if (!stateObj.TryReadChar(out buff[offst + ii])) + { + return false; + } + } + + stateObj._longlenleft -= ((ulong)charsRead << 1); + return true; + } + + internal int ReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserStateObject stateObj) + { + int charsRead; + Debug.Assert(stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); + bool result = TryReadPlpUnicodeChars(ref buff, offst, len, stateObj, out charsRead); + if (!result) + { throw SQL.SynchronousCallMayNotPend(); } + return charsRead; + } + + // Reads the requested number of chars from a plp data stream, or the entire data if + // requested length is -1 or larger than the actual length of data. First call to this method + // should be preceeded by a call to ReadPlpLength or ReadDataLength. + // Returns the actual chars read. + internal bool TryReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserStateObject stateObj, out int totalCharsRead) + { + int charsRead = 0; + int charsLeft = 0; + char[] newbuf; + + if (stateObj._longlen == 0) + { + Debug.Assert(stateObj._longlenleft == 0); + totalCharsRead = 0; + return true; // No data + } + + Debug.Assert(((ulong)stateObj._longlen != TdsEnums.SQL_PLP_NULL), + "Out of sync plp read request"); + + Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpUnicodeChars()!"); + charsLeft = len; + + // If total length is known up front, allocate the whole buffer in one shot instead of realloc'ing and copying over each time + if (buff == null && stateObj._longlen != TdsEnums.SQL_PLP_UNKNOWNLEN) + { + buff = new char[(int)Math.Min((int)stateObj._longlen, len)]; + } + + if (stateObj._longlenleft == 0) + { + ulong ignored; + if (!stateObj.TryReadPlpLength(false, out ignored)) + { + totalCharsRead = 0; + return false; + } + if (stateObj._longlenleft == 0) + { // Data read complete + totalCharsRead = 0; + return true; + } + } + + totalCharsRead = 0; + + while (charsLeft > 0) + { + charsRead = (int)Math.Min((stateObj._longlenleft + 1) >> 1, (ulong)charsLeft); + if ((buff == null) || (buff.Length < (offst + charsRead))) + { + // Grow the array + newbuf = new char[offst + charsRead]; + if (buff != null) + { + Buffer.BlockCopy(buff, 0, newbuf, 0, offst * 2); + } + buff = newbuf; + } + if (charsRead > 0) + { + if (!TryReadPlpUnicodeCharsChunk(buff, offst, charsRead, stateObj, out charsRead)) + { + return false; + } + charsLeft -= charsRead; + offst += charsRead; + totalCharsRead += charsRead; + } + // Special case single byte left + if (stateObj._longlenleft == 1 && (charsLeft > 0)) + { + byte b1; + if (!stateObj.TryReadByte(out b1)) + { + return false; + } + stateObj._longlenleft--; + ulong ignored; + if (!stateObj.TryReadPlpLength(false, out ignored)) + { + return false; + } + Debug.Assert((stateObj._longlenleft != 0), "ReadPlpUnicodeChars: Odd byte left at the end!"); + byte b2; + if (!stateObj.TryReadByte(out b2)) + { + return false; + } + stateObj._longlenleft--; + // Put it at the end of the array. At this point we know we have an extra byte. + buff[offst] = (char)(((b2 & 0xff) << 8) + (b1 & 0xff)); + offst = checked((int)offst + 1); + charsRead++; + charsLeft--; + totalCharsRead++; + } + if (stateObj._longlenleft == 0) + { // Read the next chunk or cleanup state if hit the end + ulong ignored; + if (!stateObj.TryReadPlpLength(false, out ignored)) + { + return false; + } + } + + if (stateObj._longlenleft == 0) // Data read complete + break; + } + return true; + } + + internal int ReadPlpAnsiChars(ref char[] buff, int offst, int len, SqlMetaDataPriv metadata, TdsParserStateObject stateObj) + { + int charsRead = 0; + int charsLeft = 0; + int bytesRead = 0; + int totalcharsRead = 0; + + if (stateObj._longlen == 0) + { + Debug.Assert(stateObj._longlenleft == 0); + return 0; // No data + } + + Debug.Assert(((ulong)stateObj._longlen != TdsEnums.SQL_PLP_NULL), + "Out of sync plp read request"); + + Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpAnsiChars()!"); + charsLeft = len; + + if (stateObj._longlenleft == 0) + { + stateObj.ReadPlpLength(false); + if (stateObj._longlenleft == 0) + {// Data read complete + stateObj._plpdecoder = null; + return 0; + } + } + + if (stateObj._plpdecoder == null) + { + Encoding enc = metadata.encoding; + + if (enc == null) + { + if (null == _defaultEncoding) + { + ThrowUnsupportedCollationEncountered(stateObj); + + } + + enc = _defaultEncoding; + } + stateObj._plpdecoder = enc.GetDecoder(); + } + + while (charsLeft > 0) + { + bytesRead = (int)Math.Min(stateObj._longlenleft, (ulong)charsLeft); + if ((stateObj._bTmp == null) || (stateObj._bTmp.Length < bytesRead)) + { + // Grow the array + stateObj._bTmp = new byte[bytesRead]; + } + + bytesRead = stateObj.ReadPlpBytesChunk(stateObj._bTmp, 0, bytesRead); + + charsRead = stateObj._plpdecoder.GetChars(stateObj._bTmp, 0, bytesRead, buff, offst); + charsLeft -= charsRead; + offst += charsRead; + totalcharsRead += charsRead; + if (stateObj._longlenleft == 0) // Read the next chunk or cleanup state if hit the end + stateObj.ReadPlpLength(false); + + if (stateObj._longlenleft == 0) + { // Data read complete + stateObj._plpdecoder = null; + break; + } + } + return (totalcharsRead); + } + + // ensure value is not null and does not have an NBC bit set for it before using this method + internal ulong SkipPlpValue(ulong cb, TdsParserStateObject stateObj) + { + ulong skipped; + Debug.Assert(stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); + bool result = TrySkipPlpValue(cb, stateObj, out skipped); + if (!result) + { throw SQL.SynchronousCallMayNotPend(); } + return skipped; + } + + internal bool TrySkipPlpValue(ulong cb, TdsParserStateObject stateObj, out ulong totalBytesSkipped) + { + // Read and skip cb bytes or until ReadPlpLength returns 0. + int bytesSkipped; + totalBytesSkipped = 0; + + if (stateObj._longlenleft == 0) + { + ulong ignored; + if (!stateObj.TryReadPlpLength(false, out ignored)) + { + return false; + } + } + + while ((totalBytesSkipped < cb) && + (stateObj._longlenleft > 0)) + { + if (stateObj._longlenleft > Int32.MaxValue) + bytesSkipped = Int32.MaxValue; + else + bytesSkipped = (int)stateObj._longlenleft; + bytesSkipped = ((cb - totalBytesSkipped) < (ulong)bytesSkipped) ? (int)(cb - totalBytesSkipped) : bytesSkipped; + + if (!stateObj.TrySkipBytes(bytesSkipped)) + { + return false; + } + stateObj._longlenleft -= (ulong)bytesSkipped; + totalBytesSkipped += (ulong)bytesSkipped; + + if (stateObj._longlenleft == 0) + { + ulong ignored; + if (!stateObj.TryReadPlpLength(false, out ignored)) + { + return false; + } + } + } + + return true; + } + + internal ulong PlpBytesLeft(TdsParserStateObject stateObj) + { + if ((stateObj._longlen != 0) && (stateObj._longlenleft == 0)) + stateObj.ReadPlpLength(false); + + return stateObj._longlenleft; + } + + internal bool TryPlpBytesLeft(TdsParserStateObject stateObj, out ulong left) + { + if ((stateObj._longlen != 0) && (stateObj._longlenleft == 0)) + { + if (!stateObj.TryReadPlpLength(false, out left)) + { + return false; + } + } + + left = stateObj._longlenleft; + return true; + } + + private const ulong _indeterminateSize = 0xffffffffffffffff; // Represents unknown size + + internal ulong PlpBytesTotalLength(TdsParserStateObject stateObj) + { + if (stateObj._longlen == TdsEnums.SQL_PLP_UNKNOWNLEN) + return _indeterminateSize; + else if (stateObj._longlen == TdsEnums.SQL_PLP_NULL) + return 0; + + return stateObj._longlen; + } + + const string StateTraceFormatString = "\n\t" + + " _physicalStateObj = {0}\n\t" + + " _pMarsPhysicalConObj = {1}\n\t" + + " _state = {2}\n\t" + + " _server = {3}\n\t" + + " _fResetConnection = {4}\n\t" + + " _defaultCollation = {5}\n\t" + + " _defaultCodePage = {6}\n\t" + + " _defaultLCID = {7}\n\t" + + " _defaultEncoding = {8}\n\t" + + " _encryptionOption = {10}\n\t" + + " _currentTransaction = {11}\n\t" + + " _pendingTransaction = {12}\n\t" + + " _retainedTransactionId = {13}\n\t" + + " _nonTransactedOpenResultCount = {14}\n\t" + + " _connHandler = {15}\n\t" + + " _fMARS = {16}\n\t" + + " _sessionPool = {17}\n\t" + + " _isShiloh = {18}\n\t" + + " _isShilohSP1 = {19}\n\t" + + " _isYukon = {20}\n\t" + + " _sniSpnBuffer = {21}\n\t" + + " _errors = {22}\n\t" + + " _warnings = {23}\n\t" + + " _attentionErrors = {24}\n\t" + + " _attentionWarnings = {25}\n\t" + + " _statistics = {26}\n\t" + + " _statisticsIsInTransaction = {27}\n\t" + + " _fPreserveTransaction = {28}" + + " _fParallel = {29}" + ; + internal string TraceString() + { + return string.Format(/*IFormatProvider*/ null, + StateTraceFormatString, + null == _physicalStateObj ? bool.TrueString : bool.FalseString, + null == _pMarsPhysicalConObj ? bool.TrueString : bool.FalseString, + _state, + _server, + _fResetConnection ? bool.TrueString : bool.FalseString, + null == _defaultCollation ? "(null)" : _defaultCollation.TraceString(), + _defaultCodePage, + _defaultLCID, + TraceObjectClass(_defaultEncoding), + "", + _encryptionOption, + null == _currentTransaction ? "(null)" : _currentTransaction.TraceString(), + null == _pendingTransaction ? "(null)" : _pendingTransaction.TraceString(), + _retainedTransactionId, + _nonTransactedOpenResultCount, + null == _connHandler ? "(null)" : _connHandler.ObjectID.ToString((IFormatProvider)null), + _fMARS ? bool.TrueString : bool.FalseString, + null == _sessionPool ? "(null)" : _sessionPool.TraceString(), + _isShiloh ? bool.TrueString : bool.FalseString, + _isShilohSP1 ? bool.TrueString : bool.FalseString, + _isYukon ? bool.TrueString : bool.FalseString, + null == _sniSpnBuffer ? "(null)" : _sniSpnBuffer.Length.ToString((IFormatProvider)null), + _physicalStateObj != null ? "(null)" : _physicalStateObj.ErrorCount.ToString((IFormatProvider)null), + _physicalStateObj != null ? "(null)" : _physicalStateObj.WarningCount.ToString((IFormatProvider)null), + _physicalStateObj != null ? "(null)" : _physicalStateObj.PreAttentionErrorCount.ToString((IFormatProvider)null), + _physicalStateObj != null ? "(null)" : _physicalStateObj.PreAttentionWarningCount.ToString((IFormatProvider)null), + null == _statistics ? bool.TrueString : bool.FalseString, + _statisticsIsInTransaction ? bool.TrueString : bool.FalseString, + _fPreserveTransaction ? bool.TrueString : bool.FalseString, + null == _connHandler ? "(null)" : _connHandler.ConnectionOptions.MultiSubnetFailover.ToString((IFormatProvider)null), + null == _connHandler ? "(null)" : _connHandler.ConnectionOptions.TransparentNetworkIPResolution.ToString((IFormatProvider)null)); + } + + private string TraceObjectClass(object instance) + { + if (null == instance) + { + return "(null)"; + } + else + { + return instance.GetType().ToString(); + } + } + + private static IntPtr ClientCertificateDelegate(IntPtr ptrContext) + { + GCHandle clientDelegate = GCHandle.FromIntPtr(ptrContext); + + try + { + ClientCertificateRetrievalCallback clientCallback = (ClientCertificateRetrievalCallback)clientDelegate.Target; + + X509Certificate2 cert = clientCallback(); + if (cert != null) + { + return cert.Handle; + } + else + { + return IntPtr.Zero; + } + } + catch + { + // Currently exceptions are not marshalled back. + // + Debug.Assert(false); + return IntPtr.Zero; + } + } + } // tdsparser +}//namespace diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 22be0d9a27..7c9597f6d1 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -28,26 +28,8 @@ © Microsoft Corporation. All rights reserved. sqlclient microsoft.data.sqlclient - - - - - - - - - - - - - - - - - - - - + + From 4c37241889dea3eca5a8b812474eb53c9a68aa2d Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Thu, 4 Jun 2020 15:45:38 -0700 Subject: [PATCH 20/26] Improved warning --- .../SqlClientLogger.xml | 7 +++++++ .../src/Microsoft/Data/SqlClient/TdsParser.cs | 19 +++++++++---------- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 18 ++++++++---------- .../Data/SqlClient/SqlClientLogger.cs | 15 +++++++++++++-- 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlClientLogger.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlClientLogger.xml index 229f5eee58..424027bef6 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlClientLogger.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlClientLogger.xml @@ -37,5 +37,12 @@ Logs information through a specified method of the current instance type. To be added. + + The type to be logged. + The logging method. + The message to be logged. + Logs warning through a specified method of the current instance type. + To be added. + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 83ee4ed3f8..c3e32cdf31 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Reflection; using System.Security.Authentication; using System.Text; using System.Threading; @@ -20,6 +21,7 @@ using Microsoft.Data.SqlClient.DataClassification; using Microsoft.Data.SqlClient.Server; using Microsoft.Data.SqlTypes; +using Newtonsoft.Json.Serialization; namespace Microsoft.Data.SqlClient { @@ -40,6 +42,9 @@ internal struct SNIErrorDetails internal sealed partial class TdsParser { private static int _objectTypeCount; // EventSource counter + private readonly SqlClientLogger _logger = new SqlClientLogger(); + private readonly string _typeName; + internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount); internal int ObjectID => _objectID; @@ -175,6 +180,7 @@ internal TdsParser(bool MARS, bool fAsynchronous) _physicalStateObj = TdsParserStateObjectFactory.Singleton.CreateTdsParserStateObject(this); DataClassificationVersion = TdsEnums.DATA_CLASSIFICATION_NOT_ENABLED; + _typeName = GetType().Name; } internal SqlInternalConnectionTds Connection @@ -905,17 +911,10 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus WaitForSSLHandShakeToComplete(ref error, ref protocolVersion); SslProtocols protocol = (SslProtocols)protocolVersion; - string warning = protocol.GetProtocolWarning(); - if(!string.IsNullOrEmpty(warning)) + string warningMessage = protocol.GetProtocolWarning(); + if(!string.IsNullOrEmpty(warningMessage)) { - ConsoleColor foreground = Console.ForegroundColor; - ConsoleColor background = Console.BackgroundColor; - Console.ForegroundColor = ConsoleColor.Yellow; - Console.BackgroundColor = ConsoleColor.Black; - Console.Out.WriteLine(warning); - SqlClientEventSource.Log.TraceEvent(" {0}, {1}", ObjectID, warning); - Console.ForegroundColor = foreground; - Console.BackgroundColor = background; + _logger.LogWarning(_typeName, MethodBase.GetCurrentMethod().Name, warningMessage); } // create a new packet encryption changes the internal packet size diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 61fe6584bb..a08958fd8c 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; @@ -30,6 +31,9 @@ namespace Microsoft.Data.SqlClient sealed internal class TdsParser { private static int _objectTypeCount; // EventSource Counter + private readonly SqlClientLogger _logger = new SqlClientLogger(); + private readonly string _typeName; + internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); static Task completedTask; @@ -300,6 +304,7 @@ internal TdsParser(bool MARS, bool fAsynchronous) _fMARS = MARS; // may change during Connect to pre Yukon servers _physicalStateObj = new TdsParserStateObject(this); DataClassificationVersion = TdsEnums.DATA_CLASSIFICATION_NOT_ENABLED; + _typeName = GetType().Name; } internal SqlInternalConnectionTds Connection @@ -1207,17 +1212,10 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(SqlAuthenticationMethod ThrowExceptionAndWarning(_physicalStateObj); } - string warning = SslProtocolsHelper.GetProtocolWarning(protocolVersion); - if (!string.IsNullOrEmpty(warning)) + string warningMessage = SslProtocolsHelper.GetProtocolWarning(protocolVersion); + if (!string.IsNullOrEmpty(warningMessage)) { - ConsoleColor foreground = Console.ForegroundColor; - ConsoleColor background = Console.BackgroundColor; - Console.ForegroundColor = ConsoleColor.Yellow; - Console.BackgroundColor = ConsoleColor.Black; - Console.Out.WriteLine(warning); - SqlClientEventSource.Log.TraceEvent(" {0}, {1}", ObjectID, warning); - Console.ForegroundColor = foreground; - Console.BackgroundColor = background; + _logger.LogWarning(_typeName, MethodBase.GetCurrentMethod().Name, warningMessage); } // Validate server certificate diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientLogger.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientLogger.cs index 5ff2f42e75..68afb07e49 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientLogger.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientLogger.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; + namespace Microsoft.Data.SqlClient { /// @@ -10,7 +12,8 @@ public class SqlClientLogger internal enum LogLevel { Info = 0, - Error, + Warning, + Error } /// @@ -19,10 +22,18 @@ public void LogInfo(string type, string method, string message) SqlClientEventSource.Log.TraceEvent("{3}", type, method, LogLevel.Info, message); } + /// + public void LogWarning(string type, string method, string message) + { + Console.Out.WriteLine(message); + SqlClientEventSource.Log.TraceEvent("{3}", type, method, LogLevel.Warning, message); + } + /// public void LogError(string type, string method, string message) { - SqlClientEventSource.Log.TraceEvent("{3}", type, method, LogLevel.Info, message); + Console.Out.WriteLine(message); + SqlClientEventSource.Log.TraceEvent("{3}", type, method, LogLevel.Error, message); } /// From 839c9010b6bf9e69ce13652a5373ea1e716fd434 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Thu, 4 Jun 2020 17:46:43 -0700 Subject: [PATCH 21/26] Amended external functions --- .../netcore/src/Interop/SNINativeMethodWrapper.Windows.cs | 2 +- .../Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs | 2 +- .../Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs | 2 +- .../src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index 9f64f00bec..a4eed7751b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -225,7 +225,7 @@ internal struct SNI_Error internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint pProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs index 124a6d717e..edfb5e960f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs @@ -61,7 +61,7 @@ internal static class SNINativeManagedWrapperX64 internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint pProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs index 5f857ac756..89c9af997b 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs @@ -61,7 +61,7 @@ internal static class SNINativeManagedWrapperX86 internal static extern uint SNITerminate(); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] - internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion); + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint pProtocolVersion); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index fe299cd105..fefdeea4b7 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -505,11 +505,11 @@ internal static uint SNITerminate() SNINativeManagedWrapperX86.SNITerminate(); } - internal static uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint dwProtocolVersion) + internal static uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint pProtocolVersion) { return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out dwProtocolVersion) : - SNINativeManagedWrapperX86.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out dwProtocolVersion); + SNINativeManagedWrapperX64.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out pProtocolVersion) : + SNINativeManagedWrapperX86.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out pProtocolVersion); } internal static uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted) From 7953af1fce2b07bd2d221d9428fa8cab30b35cb2 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Thu, 4 Jun 2020 20:19:13 -0700 Subject: [PATCH 22/26] Addressed reviews --- .../Data/SqlClient/TdsParserHelperClasses.cs | 3 +- .../SqlClient/TdsParserStateObjectNative.cs | 2 +- .../netcore/src/Resources/SR.Designer.cs | 2 +- .../netcore/src/Resources/SR.resx | 4 +-- .../Data/SqlClient/TdsParserHelperClasses.cs | 2 +- .../netfx/src/Resources/Strings.Designer.cs | 2 +- .../netfx/src/Resources/Strings.resx | 4 +-- src/NuGet.config | 1 - tools/specs/Microsoft.Data.SqlClient.nuspec | 28 +++++++++---------- 9 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index 81e16760fa..aa02f892be 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -949,7 +949,7 @@ private static string ToFriendlyName(this SslProtocols protocol) name = "SSL 3.0"; } else if ((protocol & SslProtocols.Ssl2) == SslProtocols.Ssl2) -#pragma warning disable CS0618 // Type or member is obsolete: SSL is depricated +#pragma warning restore CS0618 // Type or member is obsolete: SSL is depricated { name = "SSL 2.0"; } @@ -960,6 +960,7 @@ private static string ToFriendlyName(this SslProtocols protocol) return name; } + public static string GetProtocolWarning(this SslProtocols protocol) { string message = string.Empty; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index 8fff136c2c..eba4b4ed2e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -14,7 +14,7 @@ namespace Microsoft.Data.SqlClient { internal class TdsParserStateObjectNative : TdsParserStateObject { - // ptotocol versions from native sni + // protocol versions from native sni [Flags] private enum NativeProtocols { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs index 62533f31c7..c1835cd9e3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs @@ -1429,7 +1429,7 @@ internal static string PlatformNotSupported_DataSqlClient { } /// - /// Looks up a localized string similar to Security Warning: The '{0}' is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later.. + /// Looks up a localized string similar to Security Warning: The negotiated '{0}' is an insecured protocol and is supported for backward compatibility only. The recommended protocol is TLS 1.2 and later.. /// internal static string SEC_ProtocolWarning { get { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx index c2327fead7..53cd651eec 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx +++ b/src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx @@ -1864,6 +1864,6 @@ The given value{0} of type {1} from the data source cannot be converted to type {2} for Column {3} [{4}]. - Security Warning: The {0} is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later. + Security Warning: The negotiated {0} is an insecure protocol and is supported for backward compatibility only. The recommended protocol version is TLS 1.2 and later. - \ No newline at end of file + diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index 09ee312319..10bb6a0d58 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -1424,7 +1424,7 @@ private void ParseMultipartName() internal static class SslProtocolsHelper { - // ptotocol versions from native sni + // protocol versions from native sni [Flags] private enum NativeProtocols { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs index 63323bdf89..8c468a6b45 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs @@ -8092,7 +8092,7 @@ internal static string RecordManager_MinimumCapacity { } /// - /// Looks up a localized string similar to Security Warning: The {0} is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later.. + /// Looks up a localized string similar to Security Warning: The negotiated '{0}' is an insecured protocol and is supported for backward compatibility only. The recommended protocol is TLS 1.2 and later.. /// internal static string SEC_ProtocolWarning { get { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx index a5683b3595..aeab26eecd 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -4531,9 +4531,9 @@ UDT size must be less than {1}, size: {0} - Security Warning: The {0} is an unsecured protocol and is provided for backward compatibility only. The recommended protocol is TLS 1.2 and later. + Security Warning: The negotiated {0} is an insecure protocol and is supported for backward compatibility only. The recommended protocol version is TLS 1.2 and later. The specified value is not valid in the '{0}' enumeration. - \ No newline at end of file + diff --git a/src/NuGet.config b/src/NuGet.config index 0c7721a7d7..a86959a3b3 100644 --- a/src/NuGet.config +++ b/src/NuGet.config @@ -5,6 +5,5 @@ - diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index ef21b65735..f721d1c25e 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -9,21 +9,19 @@ MIT https://aka.ms/sqlclientproject dotnet.png - - Provides the data provider for SQL Server. These classes provide access to versions of SQL Server and encapsulate database-specific protocols, including tabular data stream (TDS) - - Commonly Used Types: - Microsoft.Data.SqlClient.SqlConnection - Microsoft.Data.SqlClient.SqlException - Microsoft.Data.SqlClient.SqlParameter - Microsoft.Data.SqlClient.SqlDataReader - Microsoft.Data.SqlClient.SqlCommand - Microsoft.Data.SqlClient.SqlTransaction - Microsoft.Data.SqlClient.SqlParameterCollection - Microsoft.Data.SqlClient.SqlClientFactory - - When using NuGet 3.x this package requires at least version 3.4. - + Provides the data provider for SQL Server. These classes provide access to versions of SQL Server and encapsulate database-specific protocols, including tabular data stream (TDS) + +Commonly Used Types: +Microsoft.Data.SqlClient.SqlConnection +Microsoft.Data.SqlClient.SqlException +Microsoft.Data.SqlClient.SqlParameter +Microsoft.Data.SqlClient.SqlDataReader +Microsoft.Data.SqlClient.SqlCommand +Microsoft.Data.SqlClient.SqlTransaction +Microsoft.Data.SqlClient.SqlParameterCollection +Microsoft.Data.SqlClient.SqlClientFactory + +When using NuGet 3.x this package requires at least version 3.4. https://go.microsoft.com/fwlink/?linkid=2090501 © Microsoft Corporation. All rights reserved. sqlclient microsoft.data.sqlclient From 8b0870ab4677bcb2852d2ff8fcdb28dd8aba56da Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Mon, 8 Jun 2020 18:03:35 -0700 Subject: [PATCH 23/26] Reverted the M.D.S.nuspec --- tools/specs/Microsoft.Data.SqlClient.nuspec | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index f721d1c25e..41e7f643c9 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -74,24 +74,24 @@ When using NuGet 3.x this package requires at least version 3.4. - - - + + + - - - + + + - - - + + + - - - + + + From 84ca69524a09444b02730523f6c8d6c40ceee473 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 9 Jun 2020 09:53:17 -0700 Subject: [PATCH 24/26] Added summary --- .../src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs | 5 +++++ .../netfx/src/Microsoft/Data/SqlClient/TdsParser.cs | 1 - .../src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index aa02f892be..66c0966e7d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -961,6 +961,11 @@ private static string ToFriendlyName(this SslProtocols protocol) return name; } + /// + /// check the negotiated secure protocol if it's under TLS 1.2 + /// + /// + /// Localized warning message public static string GetProtocolWarning(this SslProtocols protocol) { string message = string.Empty; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index bcb3cf125a..bcffe5b2cb 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1219,7 +1219,6 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(SqlAuthenticationMethod } // Validate server certificate - // if (serverCallback != null) { X509Certificate2 serverCert = null; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index 10bb6a0d58..873aeff914 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -1488,6 +1488,11 @@ private static string ToFriendlyName(this NativeProtocols protocol) return name; } + /// + /// check the negotiated secure protocol if it's under TLS 1.2 + /// + /// + /// Localized warning message public static string GetProtocolWarning(uint protocol) { var nativeProtocol = (NativeProtocols)protocol; From 35b7ad61f53abb9088ec42aed8fe3f2cab11ccf0 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 9 Jun 2020 12:30:49 -0700 Subject: [PATCH 25/26] Amended document --- doc/snippets/Microsoft.Data.SqlClient/SqlClientLogger.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlClientLogger.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlClientLogger.xml index 424027bef6..c093bbd505 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlClientLogger.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlClientLogger.xml @@ -42,7 +42,6 @@ The logging method. The message to be logged. Logs warning through a specified method of the current instance type. - To be added. From 87fb742372216b35f9191af0c18dd84b16414ee8 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 9 Jun 2020 14:48:54 -0700 Subject: [PATCH 26/26] Address reviews --- .../Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs | 6 +----- .../Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs index 633810bf43..6e25589986 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs @@ -205,11 +205,7 @@ internal override uint EnableMars(ref uint info) return TdsEnums.SNI_ERROR; } - internal override uint EnableSsl(ref uint info) - { - uint result = SNIProxy.Singleton.EnableSsl(Handle, info); - return result; - } + internal override uint EnableSsl(ref uint info) => SNIProxy.Singleton.EnableSsl(Handle, info); internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) => SNIProxy.Singleton.SetConnectionBufferSize(Handle, unsignedPacketSize); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index eba4b4ed2e..a38b5524df 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -320,8 +320,7 @@ internal override uint EnableMars(ref uint info) internal override uint EnableSsl(ref uint info) { // Add SSL (Encryption) SNI provider. - uint result = SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SSL_PROV, ref info); - return result; + return SNINativeMethodWrapper.SNIAddProvider(Handle, SNINativeMethodWrapper.ProviderEnum.SSL_PROV, ref info); } internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize)