Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEgor Bogatov <egorbo@gmail.com>2019-10-23 23:08:50 +0300
committerSteve Pfister <steveisok@users.noreply.github.com>2019-10-23 23:08:50 +0300
commitfb41040a9ee62f266e7c6684897b6b0368fdfff1 (patch)
treeb13809ff855f5de7a57a3932c40d0304548fa7c1 /src
parent8e3b279377d1f01d2d089f24548e33855bf6502e (diff)
Update GSS/NTLM-related sources (from .NET Core 3.0 and 2.2) (#362)
Diffstat (limited to 'src')
-rw-r--r--src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs45
-rw-r--r--src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssBuffer.cs6
-rw-r--r--src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.Initialization.cs2
-rw-r--r--src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs261
-rw-r--r--src/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs2
-rw-r--r--src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs2
-rw-r--r--src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs2
-rw-r--r--src/Native/Unix/System.Net.Security.Native/pal_gssapi.c164
-rw-r--r--src/Native/Unix/System.Net.Security.Native/pal_gssapi.h31
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs41
10 files changed, 409 insertions, 147 deletions
diff --git a/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs b/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs
index 985a971dd4..b6ea34d647 100644
--- a/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs
+++ b/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs
@@ -15,9 +15,14 @@ internal static partial class Interop
{
private readonly Status _minorStatus;
+ public Status MajorStatus
+ {
+ get { return (Status)HResult; }
+ }
+
public Status MinorStatus
{
- get { return _minorStatus;}
+ get { return _minorStatus; }
}
public GssApiException(string message) : base(message)
@@ -25,20 +30,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;
+ }
+
+ 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)
+ 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)
@@ -60,4 +89,4 @@ internal static partial class Interop
}
}
}
-}
+} \ No newline at end of file
diff --git a/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssBuffer.cs b/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssBuffer.cs
index 3168200d7e..231bd2071a 100644
--- a/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssBuffer.cs
+++ b/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssBuffer.cs
@@ -14,7 +14,7 @@ internal static partial class Interop
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct GssBuffer : IDisposable
{
- internal UInt64 _length;
+ internal ulong _length;
internal IntPtr _data;
internal int Copy(byte[] destination, int offset)
@@ -66,11 +66,11 @@ internal static partial class Interop
#if DEBUG
static GssBuffer()
{
- // Verify managed size on both 32-bit and 64-bit matches the PAL_GssBuffer
+ // Verify managed size on both 32-bit and 64-bit matches the PAL_GssBuffer
// native struct size, which is also padded on 32-bit.
Debug.Assert(Marshal.SizeOf<GssBuffer>() == 16);
}
#endif
}
}
-}
+} \ No newline at end of file
diff --git a/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.Initialization.cs b/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.Initialization.cs
index 44ae8a66ee..3794522485 100644
--- a/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.Initialization.cs
+++ b/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.Initialization.cs
@@ -38,4 +38,4 @@ internal static partial class Interop
// No-op that exists to provide a hook for other static constructors
}
}
-}
+} \ No newline at end of file
diff --git a/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs b/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs
index 95d159256a..753c6be69b 100644
--- a/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs
+++ b/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs
@@ -12,65 +12,55 @@ internal static partial class Interop
{
internal static partial class NetSecurityNative
{
-#if ENABLE_GSS
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ReleaseGssBuffer")]
- internal static extern void ReleaseGssBuffer(
+#if !ENABLE_GSS
+ internal static void ReleaseGssBuffer(
IntPtr bufferPtr,
- UInt64 length);
+ ulong length) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_DisplayMinorStatus")]
- internal static extern Status DisplayMinorStatus(
+ internal static Status DisplayMinorStatus(
out Status minorStatus,
Status statusValue,
- ref GssBuffer buffer);
+ ref GssBuffer buffer) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_DisplayMajorStatus")]
- internal static extern Status DisplayMajorStatus(
+ internal static Status DisplayMajorStatus(
out Status minorStatus,
Status statusValue,
- ref GssBuffer buffer);
+ ref GssBuffer buffer) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ImportUserName")]
- internal static extern Status ImportUserName(
+ internal static Status ImportUserName(
out Status minorStatus,
string inputName,
int inputNameByteCount,
- out SafeGssNameHandle outputName);
+ out SafeGssNameHandle outputName) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ImportPrincipalName")]
- internal static extern Status ImportPrincipalName(
+ internal static Status ImportPrincipalName(
out Status minorStatus,
string inputName,
int inputNameByteCount,
- out SafeGssNameHandle outputName);
+ out SafeGssNameHandle outputName) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ReleaseName")]
- internal static extern Status ReleaseName(
+ internal static Status ReleaseName(
out Status minorStatus,
- ref IntPtr inputName);
+ ref IntPtr inputName) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_InitiateCredSpNego")]
- internal static extern Status InitiateCredSpNego(
+ internal static Status InitiateCredSpNego(
out Status minorStatus,
SafeGssNameHandle desiredName,
- out SafeGssCredHandle outputCredHandle);
+ out SafeGssCredHandle outputCredHandle) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_InitiateCredWithPassword")]
- internal static extern Status InitiateCredWithPassword(
+ internal static Status InitiateCredWithPassword(
out Status minorStatus,
bool isNtlm,
SafeGssNameHandle desiredName,
string password,
int passwordLen,
- out SafeGssCredHandle outputCredHandle);
+ out SafeGssCredHandle outputCredHandle) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ReleaseCred")]
- internal static extern Status ReleaseCred(
+ internal static Status ReleaseCred(
out Status minorStatus,
- ref IntPtr credHandle);
+ ref IntPtr credHandle) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_InitSecContext")]
- internal static extern Status InitSecContext(
+ internal static Status InitSecContext(
out Status minorStatus,
SafeGssCredHandle initiatorCredHandle,
ref SafeGssContextHandle contextHandle,
@@ -81,119 +71,115 @@ internal static partial class Interop
int inputLength,
ref GssBuffer token,
out uint retFlags,
- out int isNtlmUsed);
+ out int isNtlmUsed) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_AcceptSecContext")]
- internal static extern Status AcceptSecContext(
+ internal static Status InitSecContext(
out Status minorStatus,
- ref SafeGssContextHandle acceptContextHandle,
+ SafeGssCredHandle initiatorCredHandle,
+ ref SafeGssContextHandle contextHandle,
+ bool isNtlmOnly,
+ IntPtr cbt,
+ int cbtSize,
+ SafeGssNameHandle targetName,
+ uint reqFlags,
byte[] inputBytes,
int inputLength,
- ref GssBuffer token);
+ ref GssBuffer token,
+ out uint retFlags,
+ out int isNtlmUsed) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_DeleteSecContext")]
- internal static extern Status DeleteSecContext(
+ internal static Status AcceptSecContext(
out Status minorStatus,
- ref IntPtr contextHandle);
+ ref SafeGssContextHandle acceptContextHandle,
+ byte[] inputBytes,
+ int inputLength,
+ ref GssBuffer token,
+ out uint retFlags) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_Wrap")]
- private static extern Status Wrap(
+ internal static Status DeleteSecContext(
out Status minorStatus,
- SafeGssContextHandle contextHandle,
- bool isEncrypt,
- byte[] inputBytes,
- int offset,
- int count,
- ref GssBuffer outBuffer);
+ ref IntPtr contextHandle) => throw new PlatformNotSupportedException ();
- [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_Unwrap")]
- private static extern Status Unwrap(
+ internal static Status GetUser(
out Status minorStatus,
- SafeGssContextHandle contextHandle,
- byte[] inputBytes,
- int offset,
- int count,
- ref GssBuffer outBuffer);
+ SafeGssContextHandle acceptContextHandle,
+ ref GssBuffer token) => throw new PlatformNotSupportedException ();
- internal static Status WrapBuffer(
+ private static Status Wrap(
out Status minorStatus,
SafeGssContextHandle contextHandle,
bool isEncrypt,
byte[] inputBytes,
int offset,
int count,
- ref GssBuffer outBuffer)
- {
- Debug.Assert(inputBytes != null, "inputBytes must be valid value");
- Debug.Assert(offset >= 0 && offset <= inputBytes.Length, "offset must be valid");
- Debug.Assert(count >= 0 && count <= (inputBytes.Length - offset), "count must be valid");
+ ref GssBuffer outBuffer) => throw new PlatformNotSupportedException ();
- return Wrap(out minorStatus, contextHandle, isEncrypt, inputBytes, offset, count, ref outBuffer);
- }
-
- internal static Status UnwrapBuffer(
+ private static Status Unwrap(
out Status minorStatus,
SafeGssContextHandle contextHandle,
byte[] inputBytes,
int offset,
int count,
- ref GssBuffer outBuffer)
- {
- Debug.Assert(inputBytes != null, "inputBytes must be valid value");
- Debug.Assert(offset >= 0 && offset <= inputBytes.Length, "offset must be valid");
- Debug.Assert(count >= 0 && count <= inputBytes.Length, "count must be valid");
-
- return Unwrap(out minorStatus, contextHandle, inputBytes, offset, count, ref outBuffer);
- }
+ ref GssBuffer outBuffer) => throw new PlatformNotSupportedException ();
#else
- internal static void ReleaseGssBuffer (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ReleaseGssBuffer")]
+ internal static extern void ReleaseGssBuffer(
IntPtr bufferPtr,
- UInt64 length) => throw new NotSupportedException ();
+ ulong length);
- internal static Status DisplayMinorStatus (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_DisplayMinorStatus")]
+ internal static extern Status DisplayMinorStatus(
out Status minorStatus,
Status statusValue,
- ref GssBuffer buffer) => throw new NotSupportedException ();
+ ref GssBuffer buffer);
- internal static Status DisplayMajorStatus (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_DisplayMajorStatus")]
+ internal static extern Status DisplayMajorStatus(
out Status minorStatus,
Status statusValue,
- ref GssBuffer buffer) => throw new NotSupportedException ();
+ ref GssBuffer buffer);
- internal static Status ImportUserName (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ImportUserName")]
+ internal static extern Status ImportUserName(
out Status minorStatus,
string inputName,
int inputNameByteCount,
- out SafeGssNameHandle outputName) => throw new NotSupportedException ();
+ out SafeGssNameHandle outputName);
- internal static Status ImportPrincipalName (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ImportPrincipalName")]
+ internal static extern Status ImportPrincipalName(
out Status minorStatus,
string inputName,
int inputNameByteCount,
- out SafeGssNameHandle outputName) => throw new NotSupportedException ();
+ out SafeGssNameHandle outputName);
- internal static Status ReleaseName (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ReleaseName")]
+ internal static extern Status ReleaseName(
out Status minorStatus,
- ref IntPtr inputName) => throw new NotSupportedException ();
+ ref IntPtr inputName);
- internal static Status InitiateCredSpNego (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_InitiateCredSpNego")]
+ internal static extern Status InitiateCredSpNego(
out Status minorStatus,
SafeGssNameHandle desiredName,
- out SafeGssCredHandle outputCredHandle) => throw new NotSupportedException ();
+ out SafeGssCredHandle outputCredHandle);
- internal static Status InitiateCredWithPassword (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_InitiateCredWithPassword")]
+ internal static extern Status InitiateCredWithPassword(
out Status minorStatus,
bool isNtlm,
SafeGssNameHandle desiredName,
string password,
int passwordLen,
- out SafeGssCredHandle outputCredHandle) => throw new NotSupportedException ();
+ out SafeGssCredHandle outputCredHandle);
- internal static Status ReleaseCred (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_ReleaseCred")]
+ internal static extern Status ReleaseCred(
out Status minorStatus,
- ref IntPtr credHandle) => throw new NotSupportedException ();
+ ref IntPtr credHandle);
- internal static Status InitSecContext (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_InitSecContext")]
+ internal static extern Status InitSecContext(
out Status minorStatus,
SafeGssCredHandle initiatorCredHandle,
ref SafeGssContextHandle contextHandle,
@@ -204,58 +190,121 @@ internal static partial class Interop
int inputLength,
ref GssBuffer token,
out uint retFlags,
- out int isNtlmUsed) => throw new NotSupportedException ();
+ out int isNtlmUsed);
- internal static Status AcceptSecContext (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_InitSecContextEx")]
+ internal static extern Status InitSecContext(
+ out Status minorStatus,
+ SafeGssCredHandle initiatorCredHandle,
+ ref SafeGssContextHandle contextHandle,
+ bool isNtlmOnly,
+ IntPtr cbt,
+ int cbtSize,
+ SafeGssNameHandle targetName,
+ uint reqFlags,
+ byte[] inputBytes,
+ int inputLength,
+ ref GssBuffer token,
+ out uint retFlags,
+ out int isNtlmUsed);
+
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_AcceptSecContext")]
+ internal static extern Status AcceptSecContext(
out Status minorStatus,
ref SafeGssContextHandle acceptContextHandle,
byte[] inputBytes,
int inputLength,
- ref GssBuffer token) => throw new NotSupportedException ();
+ ref GssBuffer token,
+ out uint retFlags);
+
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_DeleteSecContext")]
+ internal static extern Status DeleteSecContext(
+ out Status minorStatus,
+ ref IntPtr contextHandle);
- internal static Status DeleteSecContext (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_GetUser")]
+ internal static extern Status GetUser(
out Status minorStatus,
- ref IntPtr contextHandle) => throw new NotSupportedException ();
+ SafeGssContextHandle acceptContextHandle,
+ ref GssBuffer token);
- static Status Wrap(
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_Wrap")]
+ private static extern Status Wrap(
out Status minorStatus,
SafeGssContextHandle contextHandle,
bool isEncrypt,
byte[] inputBytes,
int offset,
int count,
- ref GssBuffer outBuffer) => throw new NotSupportedException ();
+ ref GssBuffer outBuffer);
- static Status Unwrap (
+ [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_Unwrap")]
+ private static extern Status Unwrap(
out Status minorStatus,
SafeGssContextHandle contextHandle,
byte[] inputBytes,
int offset,
int count,
- ref GssBuffer outBuffer) => throw new NotSupportedException ();
+ ref GssBuffer outBuffer);
+#endif
- internal static Status WrapBuffer (
+ internal static Status WrapBuffer(
out Status minorStatus,
SafeGssContextHandle contextHandle,
bool isEncrypt,
byte[] inputBytes,
int offset,
int count,
- ref GssBuffer outBuffer) => throw new NotSupportedException ();
+ ref GssBuffer outBuffer)
+ {
+ Debug.Assert(inputBytes != null, "inputBytes must be valid value");
+ Debug.Assert(offset >= 0 && offset <= inputBytes.Length, "offset must be valid");
+ Debug.Assert(count >= 0 && count <= (inputBytes.Length - offset), "count must be valid");
- internal static Status UnwrapBuffer (
+ return Wrap(out minorStatus, contextHandle, isEncrypt, inputBytes, offset, count, ref outBuffer);
+ }
+
+ internal static Status UnwrapBuffer(
out Status minorStatus,
SafeGssContextHandle contextHandle,
byte[] inputBytes,
int offset,
int count,
- ref GssBuffer outBuffer) => throw new NotSupportedException ();
-#endif
+ ref GssBuffer outBuffer)
+ {
+ Debug.Assert(inputBytes != null, "inputBytes must be valid value");
+ Debug.Assert(offset >= 0 && offset <= inputBytes.Length, "offset must be valid");
+ Debug.Assert(count >= 0 && count <= inputBytes.Length, "count must be valid");
+
+ return Unwrap(out minorStatus, contextHandle, inputBytes, offset, count, ref outBuffer);
+ }
+
+ // https://www.gnu.org/software/gss/reference/gss.pdf Page 65
+ internal const int GSS_C_ROUTINE_ERROR_OFFSET = 16;
+ // https://www.gnu.org/software/gss/reference/gss.pdf Page 9
internal enum Status : uint
{
GSS_S_COMPLETE = 0,
- GSS_S_CONTINUE_NEEDED = 1
+ GSS_S_CONTINUE_NEEDED = 1,
+ GSS_S_BAD_MECH = 1 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_BAD_NAME = 2 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_BAD_NAMETYPE = 3 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_BAD_BINDINGS = 4 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_BAD_STATUS = 5 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_BAD_SIG = 6 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_NO_CRED = 7 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_NO_CONTEXT = 8 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_DEFECTIVE_TOKEN = 9 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_DEFECTIVE_CREDENTIAL = 10 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_CREDENTIALS_EXPIRED = 11 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_CONTEXT_EXPIRED = 12 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_FAILURE = 13 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_BAD_QOP = 14 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_UNAUTHORIZED = 15 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_UNAVAILABLE = 16 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_DUPLICATE_ELEMENT = 17 << GSS_C_ROUTINE_ERROR_OFFSET,
+ GSS_S_NAME_NOT_MN = 18 << GSS_C_ROUTINE_ERROR_OFFSET,
}
[Flags]
@@ -276,4 +325,4 @@ internal static partial class Interop
GSS_C_DELEG_POLICY_FLAG = 0x8000
}
}
-}
+} \ No newline at end of file
diff --git a/src/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs b/src/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs
index 6daf3f2191..28dabc477e 100644
--- a/src/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs
+++ b/src/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs
@@ -146,4 +146,4 @@ namespace Microsoft.Win32.SafeHandles
return status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE;
}
}
-}
+} \ No newline at end of file
diff --git a/src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs b/src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs
index 74ed1b5d61..ee1f35dc98 100644
--- a/src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs
+++ b/src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs
@@ -413,4 +413,4 @@ namespace System.Net.Security
return resultSize + 4;
}
}
-}
+} \ No newline at end of file
diff --git a/src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs b/src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs
index 9b07e53e5e..ec1287c284 100644
--- a/src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs
+++ b/src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs
@@ -77,4 +77,4 @@ namespace System.Net.Security
base.Dispose(disposing);
}
}
-}
+} \ No newline at end of file
diff --git a/src/Native/Unix/System.Net.Security.Native/pal_gssapi.c b/src/Native/Unix/System.Net.Security.Native/pal_gssapi.c
index a97bce4919..97a7e0e75e 100644
--- a/src/Native/Unix/System.Net.Security.Native/pal_gssapi.c
+++ b/src/Native/Unix/System.Net.Security.Native/pal_gssapi.c
@@ -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);
@@ -154,19 +154,36 @@ uint32_t NetSecurityNative_ImportPrincipalName(uint32_t* minorStatus,
assert(outputName != NULL);
assert(*outputName == NULL);
- gss_OID nameType;
-
- if (strchr(inputName, '/') != NULL)
+ // Principal name will usually be in the form SERVICE/HOST. But SPNEGO protocol prefers
+ // GSS_C_NT_HOSTBASED_SERVICE format. That format uses '@' separator instead of '/' between
+ // service name and host name. So convert input string into that format.
+ char* ptrSlash = memchr(inputName, '/', inputNameLen);
+ char* inputNameCopy = NULL;
+ if (ptrSlash != NULL)
{
- nameType = GSS_KRB5_NT_PRINCIPAL_NAME;
+ inputNameCopy = (char*) malloc(inputNameLen);
+ if (inputNameCopy != NULL)
+ {
+ memcpy(inputNameCopy, inputName, inputNameLen);
+ inputNameCopy[ptrSlash - inputName] = '@';
+ inputName = inputNameCopy;
+ }
+ else
+ {
+ *minorStatus = 0;
+ return GSS_S_BAD_NAME;
+ }
}
- else
+
+ GssBuffer inputNameBuffer = {.length = inputNameLen, .value = inputName};
+ uint32_t result = gss_import_name(minorStatus, &inputNameBuffer, GSS_C_NT_HOSTBASED_SERVICE, outputName);
+
+ if (inputNameCopy != NULL)
{
- nameType = GSS_C_NT_HOSTBASED_SERVICE;
+ free(inputNameCopy);
}
- GssBuffer inputNameBuffer = {.length = inputNameLen, .value = inputName};
- return gss_import_name(minorStatus, &inputNameBuffer, nameType, outputName);
+ return result;
}
uint32_t NetSecurityNative_InitSecContext(uint32_t* minorStatus,
@@ -181,6 +198,35 @@ uint32_t NetSecurityNative_InitSecContext(uint32_t* minorStatus,
uint32_t* retFlags,
int32_t* isNtlmUsed)
{
+ return NetSecurityNative_InitSecContextEx(minorStatus,
+ claimantCredHandle,
+ contextHandle,
+ isNtlm,
+ NULL,
+ 0,
+ targetName,
+ reqFlags,
+ inputBytes,
+ inputLength,
+ outBuffer,
+ retFlags,
+ isNtlmUsed);
+}
+
+uint32_t NetSecurityNative_InitSecContextEx(uint32_t* minorStatus,
+ GssCredId* claimantCredHandle,
+ GssCtxId** contextHandle,
+ uint32_t isNtlm,
+ void* cbt,
+ int32_t cbtSize,
+ GssName* targetName,
+ uint32_t reqFlags,
+ uint8_t* inputBytes,
+ uint32_t inputLength,
+ PAL_GssBuffer* outBuffer,
+ uint32_t* retFlags,
+ int32_t* isNtlmUsed)
+{
assert(minorStatus != NULL);
assert(contextHandle != NULL);
assert(isNtlm == 0 || isNtlm == 1);
@@ -189,12 +235,13 @@ uint32_t NetSecurityNative_InitSecContext(uint32_t* minorStatus,
assert(outBuffer != NULL);
assert(retFlags != NULL);
assert(isNtlmUsed != NULL);
- assert(inputBytes != NULL || inputLength == 0);
+ assert(cbt != NULL || cbtSize == 0);
// Note: claimantCredHandle can be null
// Note: *contextHandle is null only in the first call and non-null in the subsequent calls
#if HAVE_GSS_SPNEGO_MECHANISM
+ gss_OID krbMech = GSS_KRB5_MECHANISM;
gss_OID desiredMech;
if (isNtlm)
{
@@ -204,9 +251,8 @@ uint32_t NetSecurityNative_InitSecContext(uint32_t* minorStatus,
{
desiredMech = GSS_SPNEGO_MECHANISM;
}
-
- gss_OID krbMech = GSS_KRB5_MECHANISM;
#else
+ gss_OID krbMech = (gss_OID)(unsigned long)gss_mech_krb5;
gss_OID_desc gss_mech_OID_desc;
if (isNtlm)
{
@@ -218,14 +264,20 @@ uint32_t NetSecurityNative_InitSecContext(uint32_t* minorStatus,
}
gss_OID desiredMech = &gss_mech_OID_desc;
- gss_OID krbMech = gss_mech_krb5;
#endif
- *isNtlmUsed = 1;
GssBuffer inputToken = {.length = inputLength, .value = inputBytes};
GssBuffer gssBuffer = {.length = 0, .value = NULL};
gss_OID_desc* outmech;
+ struct gss_channel_bindings_struct gssCbt;
+ if (cbt != NULL)
+ {
+ memset(&gssCbt, 0, sizeof(struct gss_channel_bindings_struct));
+ gssCbt.application_data.length = (size_t)cbtSize;
+ gssCbt.application_data.value = cbt;
+ }
+
uint32_t majorStatus = gss_init_sec_context(minorStatus,
claimantCredHandle,
contextHandle,
@@ -233,18 +285,14 @@ uint32_t NetSecurityNative_InitSecContext(uint32_t* minorStatus,
desiredMech,
reqFlags,
0,
- GSS_C_NO_CHANNEL_BINDINGS,
+ (cbt != NULL) ? &gssCbt : GSS_C_NO_CHANNEL_BINDINGS,
&inputToken,
&outmech,
&gssBuffer,
retFlags,
NULL);
- // Outmech can be null when gssntlmssp lib uses NTLM mechanism
- if (outmech != NULL && gss_oid_equal(outmech, krbMech) != 0)
- {
- *isNtlmUsed = 0;
- }
+ *isNtlmUsed = (isNtlm || majorStatus != GSS_S_COMPLETE || gss_oid_equal(outmech, krbMech) == 0) ? 1 : 0;
NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
return majorStatus;
@@ -254,7 +302,8 @@ uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
GssCtxId** contextHandle,
uint8_t* inputBytes,
uint32_t inputLength,
- PAL_GssBuffer* outBuffer)
+ PAL_GssBuffer* outBuffer,
+ uint32_t* retFlags)
{
assert(minorStatus != NULL);
assert(contextHandle != NULL);
@@ -273,7 +322,7 @@ uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
NULL,
NULL,
&gssBuffer,
- 0,
+ retFlags,
NULL,
NULL);
@@ -281,6 +330,44 @@ uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
return majorStatus;
}
+uint32_t NetSecurityNative_GetUser(uint32_t* minorStatus,
+ GssCtxId* contextHandle,
+ PAL_GssBuffer* outBuffer)
+{
+ assert(minorStatus != NULL);
+ assert(contextHandle != NULL);
+ assert(outBuffer != NULL);
+
+ gss_name_t srcName = GSS_C_NO_NAME;
+
+ uint32_t majorStatus = gss_inquire_context(minorStatus,
+ contextHandle,
+ &srcName,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (majorStatus == GSS_S_COMPLETE)
+ {
+ GssBuffer gssBuffer = {.length = 0, .value = NULL};
+ majorStatus = gss_display_name(minorStatus, srcName, &gssBuffer, NULL);
+ if (majorStatus == GSS_S_COMPLETE)
+ {
+ NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
+ }
+ }
+
+ if (srcName != NULL)
+ {
+ majorStatus = gss_release_name(minorStatus, &srcName);
+ }
+
+ return majorStatus;
+}
+
uint32_t NetSecurityNative_ReleaseCred(uint32_t* minorStatus, GssCredId** credHandle)
{
assert(minorStatus != NULL);
@@ -416,4 +503,37 @@ uint32_t NetSecurityNative_InitiateCredWithPassword(uint32_t* minorStatus,
{
return NetSecurityNative_AcquireCredWithPassword(
minorStatus, isNtlm, desiredName, password, passwdLen, GSS_C_INITIATE, outputCredHandle);
+}
+
+uint32_t NetSecurityNative_IsNtlmInstalled()
+{
+#if HAVE_GSS_SPNEGO_MECHANISM
+ gss_OID ntlmOid = GSS_NTLM_MECHANISM;
+#else
+ gss_OID ntlmOid = &gss_mech_ntlm_OID_desc;
+#endif
+
+ uint32_t majorStatus;
+ uint32_t minorStatus;
+ gss_OID_set mechSet;
+ gss_OID_desc oid;
+ uint32_t foundNtlm = 0;
+
+ majorStatus = gss_indicate_mechs(&minorStatus, &mechSet);
+ if (majorStatus == GSS_S_COMPLETE)
+ {
+ for (size_t i = 0; i < mechSet->count; i++)
+ {
+ oid = mechSet->elements[i];
+ if ((oid.length == ntlmOid->length) && (memcmp(oid.elements, ntlmOid->elements, oid.length) == 0))
+ {
+ foundNtlm = 1;
+ break;
+ }
+ }
+
+ gss_release_oid_set(&minorStatus, &mechSet);
+ }
+
+ return foundNtlm;
} \ No newline at end of file
diff --git a/src/Native/Unix/System.Net.Security.Native/pal_gssapi.h b/src/Native/Unix/System.Net.Security.Native/pal_gssapi.h
index 91071cf56e..5b951e7d21 100644
--- a/src/Native/Unix/System.Net.Security.Native/pal_gssapi.h
+++ b/src/Native/Unix/System.Net.Security.Native/pal_gssapi.h
@@ -115,6 +115,20 @@ DLLEXPORT uint32_t NetSecurityNative_InitSecContext(uint32_t* minorStatus,
uint32_t* retFlags,
int32_t* isNtlmUsed);
+DLLEXPORT uint32_t NetSecurityNative_InitSecContextEx(uint32_t* minorStatus,
+ GssCredId* claimantCredHandle,
+ GssCtxId** contextHandle,
+ uint32_t isNtlm,
+ void* cbt,
+ int32_t cbtSize,
+ GssName* targetName,
+ uint32_t reqFlags,
+ uint8_t* inputBytes,
+ uint32_t inputLength,
+ PAL_GssBuffer* outBuffer,
+ uint32_t* retFlags,
+ int32_t* isNtlmUsed);
+
/*
Shims the gss_accept_sec_context method.
*/
@@ -122,7 +136,8 @@ DLLEXPORT uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
GssCtxId** contextHandle,
uint8_t* inputBytes,
uint32_t inputLength,
- PAL_GssBuffer* outBuffer);
+ PAL_GssBuffer* outBuffer,
+ uint32_t* retFlags);
/*
@@ -159,4 +174,16 @@ DLLEXPORT uint32_t NetSecurityNative_InitiateCredWithPassword(uint32_t* minorSta
GssName* desiredName,
char* password,
uint32_t passwdLen,
- GssCredId** outputCredHandle); \ No newline at end of file
+ GssCredId** outputCredHandle);
+
+/*
+Shims the gss_indicate_mechs method to detect if NTLM mech is installed.
+*/
+DLLEXPORT uint32_t NetSecurityNative_IsNtlmInstalled(void);
+
+/*
+Shims gss_inquire_context and gss_display_name to get the remote user principal name.
+*/
+DLLEXPORT uint32_t NetSecurityNative_GetUser(uint32_t* minorStatus,
+ GssCtxId* contextHandle,
+ PAL_GssBuffer* outBuffer); \ No newline at end of file
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs
index 4c6d148c70..5f424ff2e9 100644
--- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Net;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
@@ -76,7 +77,44 @@ namespace System.Net.Http
string challengeData = challenge.ChallengeData;
- string spn = "HTTP/" + authUri.IdnHost;
+ // Calculate SPN (Service Principal Name) using the host name of the request.
+ // Use the request's 'Host' header if available. Otherwise, use the request uri.
+ // Ignore the 'Host' header if this is proxy authentication since we need to use
+ // the host name of the proxy itself for SPN calculation.
+ string hostName;
+ if (!isProxyAuth && request.HasHeaders && request.Headers.Host != null)
+ {
+ // Use the host name without any normalization.
+ hostName = request.Headers.Host;
+ if (NetEventSource.IsEnabled)
+ {
+ NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, Host: {hostName}");
+ }
+ }
+ else
+ {
+ // Need to use FQDN normalized host so that CNAME's are traversed.
+ // Use DNS to do the forward lookup to an A (host) record.
+ // But skip DNS lookup on IP literals. Otherwise, we would end up
+ // doing an unintended reverse DNS lookup.
+ UriHostNameType hnt = authUri.HostNameType;
+ if (hnt == UriHostNameType.IPv6 || hnt == UriHostNameType.IPv4)
+ {
+ hostName = authUri.IdnHost;
+ }
+ else
+ {
+ IPHostEntry result = await Dns.GetHostEntryAsync(authUri.IdnHost).ConfigureAwait(false);
+ hostName = result.HostName;
+ }
+ }
+
+ string spn = "HTTP/" + hostName;
+ if (NetEventSource.IsEnabled)
+ {
+ NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, SPN: {spn}");
+ }
+
ChannelBinding channelBinding = connection.TransportContext?.GetChannelBinding(ChannelBindingKind.Endpoint);
NTAuthentication authContext = new NTAuthentication(isServer:false, challenge.SchemeName, challenge.Credential, spn, ContextFlagsPal.Connection, channelBinding);
try
@@ -135,4 +173,3 @@ namespace System.Net.Http
}
}
}
-