Fix GSSAPI error handling (dotnet/corefx#34883)
authorDavid Shulman <david.shulman@microsoft.com>
Sun, 27 Jan 2019 23:41:53 +0000 (15:41 -0800)
committerGitHub <noreply@github.com>
Sun, 27 Jan 2019 23:41:53 +0000 (15:41 -0800)
This PR addresses 3 issues in GSSAPI error handling:

* Fixes an uninitialized variable when calling gss_display_status().
This was causing the major statuscode error message to always return
'An invalid status code was supplied'.

* If the minor statuscode is 0 (GSS_S_COMPLETE), we shouldn't be calling
for the minor statuscode error message text. That is why we were always getting
'Unknown error' for that text.

* Added more text (help text) to certain errors returned from GSSAPI
such as when the NTLM plugin is not installed.

No new tests were added to this PR since it requires machine changes
to test. However, I manually tested various combinations of errors
including when 'gss-ntlmssp' is installed or not.

In terms of dotnet/corefx#34877, the exception message goes from:

>GSSAPI operation failed with error - An invalid status code was supplied (Unknown error).

to

>GSSAPI operation failed with error - An unsupported mechanism was requested. NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.

Fixes dotnet/corefx#34877

Commit migrated from https://github.com/dotnet/corefx/commit/eec001d96a68376c0e504eb7635c8edec196f90f

src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs
src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs
src/libraries/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs
src/libraries/Native/Unix/System.Net.Security.Native/pal_gssapi.c
src/libraries/System.Data.SqlClient/src/Resources/Strings.resx
src/libraries/System.Net.Http/src/Resources/Strings.resx
src/libraries/System.Net.Mail/src/Resources/Strings.resx
src/libraries/System.Net.Security/src/Resources/Strings.resx
src/libraries/System.Net.Security/tests/FunctionalTests/Resources/Strings.resx

index 985a971..d4fb421 100644 (file)
@@ -25,20 +25,44 @@ internal static partial class Interop
             }
 
             public GssApiException(Status majorStatus, Status minorStatus)
-                : base(GetGssApiDisplayStatus(majorStatus, minorStatus))
+                : base(GetGssApiDisplayStatus(majorStatus, minorStatus, null))
             {
                 HResult = (int)majorStatus;
                 _minorStatus = minorStatus;
             }
 
-            private static string GetGssApiDisplayStatus(Status majorStatus, Status minorStatus)
+            public GssApiException(Status majorStatus, Status minorStatus, string helpText)
+                : base(GetGssApiDisplayStatus(majorStatus, minorStatus, helpText))
+            {
+                HResult = (int)majorStatus;
+                _minorStatus = minorStatus;
+            }
+
+            private static string GetGssApiDisplayStatus(Status majorStatus, Status minorStatus, string helpText)
             {
                 string majorError = GetGssApiDisplayStatus(majorStatus, isMinor: false);
-                string minorError = GetGssApiDisplayStatus(minorStatus, isMinor: true);
+                string errorMessage;
+
+                if (minorStatus != Status.GSS_S_COMPLETE)
+                {
+                    string minorError = GetGssApiDisplayStatus(minorStatus, isMinor: true);
+                    errorMessage = (majorError != null && minorError != null) ?
+                        SR.Format(SR.net_gssapi_operation_failed_detailed, majorError, minorError) :
+                        SR.Format(SR.net_gssapi_operation_failed, majorStatus.ToString("x"), minorStatus.ToString("x"));
+                }
+                else
+                {
+                    errorMessage = (majorError != null) ?
+                        SR.Format(SR.net_gssapi_operation_failed_detailed_majoronly, majorError) :
+                        SR.Format(SR.net_gssapi_operation_failed_majoronly, majorStatus.ToString("x"));
+                }
+
+                if (!string.IsNullOrEmpty(helpText))
+                {
+                    return errorMessage + " " + helpText;
+                }
 
-                return (majorError != null && minorError != null) ?
-                    SR.Format(SR.net_gssapi_operation_failed_detailed, majorError, minorError) :
-                    SR.Format(SR.net_gssapi_operation_failed, majorStatus.ToString("x"), minorStatus.ToString("x"));
+                return errorMessage;
             }
 
             private static string GetGssApiDisplayStatus(Status status, bool isMinor)
index ab08863..3da7cf4 100644 (file)
@@ -148,7 +148,8 @@ internal static partial class Interop
         internal enum Status : uint
         {
             GSS_S_COMPLETE = 0,
-            GSS_S_CONTINUE_NEEDED = 1
+            GSS_S_CONTINUE_NEEDED = 1,
+            GSS_S_BAD_MECH = 65536
         }
 
         [Flags]
index 6daf3f2..e90b25f 100644 (file)
@@ -100,7 +100,12 @@ namespace Microsoft.Win32.SafeHandles
                 if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                 {
                     retHandle.Dispose();
-                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
+                    throw new Interop.NetSecurityNative.GssApiException(
+                        status,
+                        minorStatus,
+                        (status == Interop.NetSecurityNative.Status.GSS_S_BAD_MECH && isNtlmOnly) ?
+                            SR.net_gssapi_ntlm_missing_plugin :
+                            null);
                 }
             }
 
index 2fec08e..cd99491 100644 (file)
@@ -111,7 +111,7 @@ static uint32_t NetSecurityNative_DisplayStatus(uint32_t* minorStatus,
     assert(minorStatus != NULL);
     assert(outBuffer != NULL);
 
-    uint32_t messageContext;
+    uint32_t messageContext = 0; // Must initialize to 0 before calling gss_display_status.
     GssBuffer gssBuffer = {.length = 0, .value = NULL};
     uint32_t majorStatus =
         gss_display_status(minorStatus, statusValue, statusType, GSS_C_NO_OID, &messageContext, &gssBuffer);
index f480f68..4f7a63a 100644 (file)
   <data name="net_gssapi_operation_failed" xml:space="preserve">
     <value>GSSAPI operation failed with status: {0} (Minor status: {1}).</value>
   </data>
+  <data name="net_gssapi_operation_failed_detailed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with error - {0}.</value>
+  </data>
+  <data name="net_gssapi_operation_failed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with status: {0}.</value>
+  </data>
+  <data name="net_gssapi_ntlm_missing_plugin" xml:space="preserve">
+    <value>NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.</value>
+  </data>
   <data name="net_ntlm_not_possible_default_cred" xml:space="preserve">
     <value>NTLM authentication is not possible with default credentials on this platform.</value>
   </data>
index 0306c4c..7bbdbe7 100644 (file)
   <data name="net_gssapi_operation_failed" xml:space="preserve">
     <value>GSSAPI operation failed with status: {0} (Minor status: {1}).</value>
   </data>
+  <data name="net_gssapi_operation_failed_detailed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with error - {0}.</value>
+  </data>
+  <data name="net_gssapi_operation_failed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with status: {0}.</value>
+  </data>
+  <data name="net_gssapi_ntlm_missing_plugin" xml:space="preserve">
+    <value>NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.</value>
+  </data>
   <data name="net_nego_channel_binding_not_supported" xml:space="preserve">
     <value>No support for channel binding on operating systems other than Windows.</value>
   </data>
index 5b3a668..1c002ca 100644 (file)
   <data name="net_gssapi_operation_failed" xml:space="preserve">
     <value>GSSAPI operation failed with status: {0} (Minor status: {1}).</value>
   </data>
+  <data name="net_gssapi_operation_failed_detailed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with error - {0}.</value>
+  </data>
+  <data name="net_gssapi_operation_failed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with status: {0}.</value>
+  </data>
+  <data name="net_gssapi_ntlm_missing_plugin" xml:space="preserve">
+    <value>NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.</value>
+  </data>
   <data name="net_nego_channel_binding_not_supported" xml:space="preserve">
     <value>No support for channel binding on operating systems other than Windows.</value>
   </data>
index 75c975e..711bbc3 100644 (file)
   <data name="net_gssapi_operation_failed" xml:space="preserve">
     <value>GSSAPI operation failed with status: {0} (Minor status: {1}).</value>
   </data>
+  <data name="net_gssapi_operation_failed_detailed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with error - {0}.</value>
+  </data>
+  <data name="net_gssapi_operation_failed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with status: {0}.</value>
+  </data>
+  <data name="net_gssapi_ntlm_missing_plugin" xml:space="preserve">
+    <value>NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.</value>
+  </data>
   <data name="net_context_buffer_too_small" xml:space="preserve">
     <value>Insufficient buffer space. Required: {0} Actual: {1}.</value>
   </data>
index a940562..fa19f81 100644 (file)
   <data name="net_gssapi_operation_failed" xml:space="preserve">
     <value>GSSAPI operation failed with status: {0} (Minor status: {1})</value>
   </data>
+  <data name="net_gssapi_operation_failed_detailed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with error - {0}.</value>
+  </data>
+  <data name="net_gssapi_operation_failed_majoronly" xml:space="preserve">
+    <value>GSSAPI operation failed with status: {0}.</value>
+  </data>
+  <data name="net_gssapi_ntlm_missing_plugin" xml:space="preserve">
+    <value>NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.</value>
+  </data>
   <data name="net_context_establishment_failed" xml:space="preserve">
     <value>GSSAPI security context establishment failed with status: {0} (Minor status: {1})</value>
   </data>