1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Diagnostics;
6 using System.Data.SqlClient.SNI;
7 
8 namespace System.Data.SqlClient
9 {
10     internal sealed partial class TdsParser
11     {
12         private static volatile bool s_fSSPILoaded = false; // bool to indicate whether library has been loaded
13 
PostReadAsyncForMars()14         internal void PostReadAsyncForMars()
15         {
16             if (TdsParserStateObjectFactory.UseManagedSNI)
17                 return;
18 
19             // HACK HACK HACK - for Async only
20             // Have to post read to initialize MARS - will get callback on this when connection goes
21             // down or is closed.
22 
23             IntPtr temp = IntPtr.Zero;
24             uint error = TdsEnums.SNI_SUCCESS;
25 
26             _pMarsPhysicalConObj.IncrementPendingCallbacks();
27             object handle = _pMarsPhysicalConObj.SessionHandle;
28             temp = (IntPtr)_pMarsPhysicalConObj.ReadAsync(out error, ref handle);
29 
30             if (temp != IntPtr.Zero)
31             {
32                 // Be sure to release packet, otherwise it will be leaked by native.
33                 _pMarsPhysicalConObj.ReleasePacket(temp);
34             }
35 
36             Debug.Assert(IntPtr.Zero == temp, "unexpected syncReadPacket without corresponding SNIPacketRelease");
37             if (TdsEnums.SNI_SUCCESS_IO_PENDING != error)
38             {
39                 Debug.Assert(TdsEnums.SNI_SUCCESS != error, "Unexpected successful read async on physical connection before enabling MARS!");
40                 _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj));
41                 ThrowExceptionAndWarning(_physicalStateObj);
42             }
43         }
44 
LoadSSPILibrary()45         private void LoadSSPILibrary()
46         {
47             if (TdsParserStateObjectFactory.UseManagedSNI)
48                 return;
49             // Outer check so we don't acquire lock once it's loaded.
50             if (!s_fSSPILoaded)
51             {
52                 lock (s_tdsParserLock)
53                 {
54                     // re-check inside lock
55                     if (!s_fSSPILoaded)
56                     {
57                         // use local for ref param to defer setting s_maxSSPILength until we know the call succeeded.
58                         UInt32 maxLength = 0;
59 
60                         if (0 != SNINativeMethodWrapper.SNISecInitPackage(ref maxLength))
61                             SSPIError(SQLMessage.SSPIInitializeError(), TdsEnums.INIT_SSPI_PACKAGE);
62 
63                         s_maxSSPILength = maxLength;
64                         s_fSSPILoaded = true;
65                     }
66                 }
67             }
68 
69             if (s_maxSSPILength > Int32.MaxValue)
70             {
71                 throw SQL.InvalidSSPIPacketSize();   // SqlBu 332503
72             }
73         }
74 
WaitForSSLHandShakeToComplete(ref uint error)75         private void WaitForSSLHandShakeToComplete(ref uint error)
76         {
77             if (TdsParserStateObjectFactory.UseManagedSNI)
78                 return;
79             // in the case where an async connection is made, encryption is used and Windows Authentication is used,
80             // wait for SSL handshake to complete, so that the SSL context is fully negotiated before we try to use its
81             // Channel Bindings as part of the Windows Authentication context build (SSL handshake must complete
82             // before calling SNISecGenClientContext).
83             error = _physicalStateObj.WaitForSSLHandShakeToComplete();
84             if (error != TdsEnums.SNI_SUCCESS)
85             {
86                 _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj));
87                 ThrowExceptionAndWarning(_physicalStateObj);
88             }
89         }
90 
GetSniErrorDetails()91         private SNIErrorDetails GetSniErrorDetails()
92         {
93             SNIErrorDetails details = new SNIErrorDetails();
94 
95             if (TdsParserStateObjectFactory.UseManagedSNI)
96             {
97                 SNIError sniError = SNIProxy.Singleton.GetLastError();
98                 details.sniErrorNumber = sniError.sniError;
99                 details.errorMessage = sniError.errorMessage;
100                 details.nativeError = sniError.nativeError;
101                 details.provider = (int)sniError.provider;
102                 details.lineNumber = sniError.lineNumber;
103                 details.function = sniError.function;
104                 details.exception = sniError.exception;
105             }
106             else
107             {
108                 SNINativeMethodWrapper.SNI_Error sniError;
109                 SNINativeMethodWrapper.SNIGetLastError(out sniError);
110                 details.sniErrorNumber = sniError.sniError;
111                 details.errorMessage = sniError.errorMessage;
112                 details.nativeError = sniError.nativeError;
113                 details.provider = (int)sniError.provider;
114                 details.lineNumber = sniError.lineNumber;
115                 details.function = sniError.function;
116             }
117             return details;
118         }
119 
120     }    // tdsparser
121 }//namespace