Skip to content

Commit

Permalink
Tracing improvements in Managed SNI (#1187)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wraith2 committed Jul 28, 2021
1 parent 0288d90 commit 4e72e43
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 379 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ namespace Microsoft.Data.SqlClient.SNI
internal sealed class LocalDB
{
private static readonly LocalDB Instance = new LocalDB();
private const string s_className = nameof(LocalDB);

//HKEY_LOCAL_MACHINE
private const string LocalDBInstalledVersionRegistryKey = "SOFTWARE\\Microsoft\\Microsoft SQL Server Local DB\\Installed Versions\\";
Expand Down Expand Up @@ -103,8 +102,7 @@ internal static string MapLocalDBErrorStateToErrorMessage(LocalDBErrorState erro
/// </summary>
private bool LoadUserInstanceDll()
{
long scopeID = SqlClientEventSource.Log.TrySNIScopeEnterEvent(s_className);
try
using (TrySNIEventScope.Create(nameof(LocalDB)))
{
// Check in a non thread-safe way if the handle is already set for performance.
if (_sqlUserInstanceLibraryHandle != null)
Expand All @@ -128,15 +126,15 @@ private bool LoadUserInstanceDll()
if (dllPath == null)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, MapLocalDBErrorStateToCode(registryQueryErrorState), MapLocalDBErrorStateToErrorMessage(registryQueryErrorState));
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "User instance DLL path is null.");
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "User instance DLL path is null.");
return false;
}

// In case the registry had an empty path for dll
if (string.IsNullOrWhiteSpace(dllPath))
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBInvalidSqlUserInstanceDllPath, Strings.SNI_ERROR_55);
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "User instance DLL path is invalid. DLL path = {0}", dllPath);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "User instance DLL path is invalid. DLL path = {0}", dllPath);
return false;
}

Expand All @@ -146,7 +144,7 @@ private bool LoadUserInstanceDll()
if (libraryHandle.IsInvalid)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBFailedToLoadDll, Strings.SNI_ERROR_56);
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "Library Handle is invalid. Could not load the dll.");
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "Library Handle is invalid. Could not load the dll.");
libraryHandle.Dispose();
return false;
}
Expand All @@ -157,7 +155,7 @@ private bool LoadUserInstanceDll()
if (_startInstanceHandle == IntPtr.Zero)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBBadRuntime, Strings.SNI_ERROR_57);
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "Was not able to load the PROC from DLL. Bad Runtime.");
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "Was not able to load the PROC from DLL. Bad Runtime.");
libraryHandle.Dispose();
return false;
}
Expand All @@ -174,14 +172,10 @@ private bool LoadUserInstanceDll()
}

_sqlUserInstanceLibraryHandle = libraryHandle;
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "User Instance DLL was loaded successfully.");
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.INFO, "User Instance DLL was loaded successfully.");
return true;
}
}
finally
{
SqlClientEventSource.Log.TrySNIScopeLeaveEvent(scopeID);
}
}

/// <summary>
Expand All @@ -191,16 +185,15 @@ private bool LoadUserInstanceDll()
/// <returns></returns>
private string GetUserInstanceDllPath(out LocalDBErrorState errorState)
{
long scopeID = SqlClientEventSource.Log.TrySNIScopeEnterEvent(s_className);
try
using (TrySNIEventScope.Create(nameof(LocalDB)))
{
string dllPath = null;
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(LocalDBInstalledVersionRegistryKey))
{
if (key == null)
{
errorState = LocalDBErrorState.NO_INSTALLATION;
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "No installation found.");
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "No installation found.");
return null;
}

Expand All @@ -215,7 +208,7 @@ private string GetUserInstanceDllPath(out LocalDBErrorState errorState)
if (!Version.TryParse(subKey, out currentKeyVersion))
{
errorState = LocalDBErrorState.INVALID_CONFIG;
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "Invalid Configuration.");
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "Invalid Configuration.");
return null;
}

Expand All @@ -229,7 +222,7 @@ private string GetUserInstanceDllPath(out LocalDBErrorState errorState)
if (latestVersion.Equals(zeroVersion))
{
errorState = LocalDBErrorState.INVALID_CONFIG;
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "Invalid Configuration.");
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "Invalid Configuration.");
return null;
}

Expand All @@ -242,7 +235,7 @@ private string GetUserInstanceDllPath(out LocalDBErrorState errorState)
if (instanceAPIPathRegistryObject == null)
{
errorState = LocalDBErrorState.NO_SQLUSERINSTANCEDLL_PATH;
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "No SQL user instance DLL. Instance API Path Registry Object Error.");
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "No SQL user instance DLL. Instance API Path Registry Object Error.");
return null;
}

Expand All @@ -251,7 +244,7 @@ private string GetUserInstanceDllPath(out LocalDBErrorState errorState)
if (valueKind != RegistryValueKind.String)
{
errorState = LocalDBErrorState.INVALID_SQLUSERINSTANCEDLL_PATH;
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "Invalid SQL user instance DLL path. Registry value kind mismatch.");
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "Invalid SQL user instance DLL path. Registry value kind mismatch.");
return null;
}

Expand All @@ -262,10 +255,6 @@ private string GetUserInstanceDllPath(out LocalDBErrorState errorState)
}
}
}
finally
{
SqlClientEventSource.Log.TrySNIScopeLeaveEvent(scopeID);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,6 @@ internal enum SNISMUXFlags : uint

internal class SNICommon
{
private const string s_className = nameof(SNICommon);

// Each error number maps to SNI_ERROR_* in String.resx
internal const int ConnTerminatedError = 2;
internal const int InvalidParameterError = 5;
Expand Down Expand Up @@ -169,12 +167,11 @@ internal class SNICommon
/// <returns>True if certificate is valid</returns>
internal static bool ValidateSslServerCertificate(string targetServerName, X509Certificate cert, SslPolicyErrors policyErrors)
{
long scopeID = SqlClientEventSource.Log.TrySNIScopeEnterEvent("SNICommon.ValidateSslServerCertificate | SNI | SCOPE | INFO | Entering Scope {0} ");
try
using (TrySNIEventScope.Create("SNICommon.ValidateSslServerCertificate | SNI | SCOPE | INFO | Entering Scope {0} "))
{
if (policyErrors == SslPolicyErrors.None)
{
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "targetServerName {0}, SSL Server certificate not validated as PolicyErrors set to None.", args0: targetServerName);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "targetServerName {0}, SSL Server certificate not validated as PolicyErrors set to None.", args0: targetServerName);
return true;
}

Expand All @@ -185,23 +182,23 @@ internal static bool ValidateSslServerCertificate(string targetServerName, X509C
// Verify that target server name matches subject in the certificate
if (targetServerName.Length > certServerName.Length)
{
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "targetServerName {0}, Target Server name is of greater length than Subject in Certificate.", args0: targetServerName);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name is of greater length than Subject in Certificate.", args0: targetServerName);
return false;
}
else if (targetServerName.Length == certServerName.Length)
{
// Both strings have the same length, so targetServerName must be a FQDN
if (!targetServerName.Equals(certServerName, StringComparison.OrdinalIgnoreCase))
{
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName);
return false;
}
}
else
{
if (string.Compare(targetServerName, 0, certServerName, 0, targetServerName.Length, StringComparison.OrdinalIgnoreCase) != 0)
{
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName);
return false;
}

Expand All @@ -211,24 +208,20 @@ internal static bool ValidateSslServerCertificate(string targetServerName, X509C
// (Names have different lengths, so the target server can't be a FQDN.)
if (certServerName[targetServerName.Length] != '.')
{
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName);
return false;
}
}
}
else
{
// Fail all other SslPolicy cases besides RemoteCertificateNameMismatch
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "targetServerName {0}, SslPolicyError {1}, SSL Policy invalidated certificate.", args0: targetServerName, args1: policyErrors);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, SslPolicyError {1}, SSL Policy invalidated certificate.", args0: targetServerName, args1: policyErrors);
return false;
}
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "targetServerName {0}, Client certificate validated successfully.", args0: targetServerName);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "targetServerName {0}, Client certificate validated successfully.", args0: targetServerName);
return true;
}
finally
{
SqlClientEventSource.Log.TrySNIScopeLeaveEvent(scopeID);
}
}

/// <summary>
Expand All @@ -241,7 +234,7 @@ internal static bool ValidateSslServerCertificate(string targetServerName, X509C
/// <returns></returns>
internal static uint ReportSNIError(SNIProviders provider, uint nativeError, uint sniError, string errorMessage)
{
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "Provider = {0}, native Error = {1}, SNI Error = {2}, Error Message = {3}", args0: provider, args1: nativeError, args2: sniError, args3: errorMessage);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Provider = {0}, native Error = {1}, SNI Error = {2}, Error Message = {3}", args0: provider, args1: nativeError, args2: sniError, args3: errorMessage);
return ReportSNIError(new SNIError(provider, nativeError, sniError, errorMessage));
}

Expand All @@ -255,7 +248,7 @@ internal static uint ReportSNIError(SNIProviders provider, uint nativeError, uin
/// <returns></returns>
internal static uint ReportSNIError(SNIProviders provider, uint sniError, Exception sniException, uint nativeErrorCode = 0)
{
SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "Provider = {0}, SNI Error = {1}, Exception = {2}", args0: provider, args1: sniError, args2: sniException?.Message);
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Provider = {0}, SNI Error = {1}, Exception = {2}", args0: provider, args1: sniError, args2: sniException?.Message);
return ReportSNIError(new SNIError(provider, sniError, sniException, nativeErrorCode));
}

Expand Down

0 comments on commit 4e72e43

Please sign in to comment.