private static SecurityStatusPal EstablishSecurityContext(
SafeFreeNegoCredentials credential,
ref SafeDeleteContext context,
string targetName,
ContextFlagsPal inFlags,
SecurityBuffer inputBuffer,
SecurityBuffer outputBuffer,
ref ContextFlagsPal outFlags)
{
bool isNtlmOnly = credential.IsNtlmOnly;
if (context == null)
{
// Empty target name causes the failure on Linux, hence passing a non-empty string
context = isNtlmOnly ? new SafeDeleteNegoContext(credential, credential.UserName) : new SafeDeleteNegoContext(credential, targetName);
}
SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context;
try
{
Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags, isServer: false);
uint outputFlags;
int isNtlmUsed;
SafeGssContextHandle contextHandle = negoContext.GssContext;
bool done = GssInitSecurityContext(
ref contextHandle,
credential.GssCredential,
isNtlmOnly,
negoContext.TargetName,
inputFlags,
inputBuffer?.token,
out outputBuffer.token,
out outputFlags,
out isNtlmUsed);
Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi");
outputBuffer.size = outputBuffer.token.Length;
outputBuffer.offset = 0;
outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags, isServer: false);
Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);
// Save the inner context handle for further calls to NetSecurity
Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);
if (null == negoContext.GssContext)
{
negoContext.SetGssContext(contextHandle);
}
// Populate protocol used for authentication
if (done)
{
negoContext.SetAuthenticationPackage(Convert.ToBoolean(isNtlmUsed));
}
SecurityStatusPalErrorCode errorCode = done ?
(negoContext.IsNtlmUsed && outputBuffer.size > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) :
SecurityStatusPalErrorCode.ContinueNeeded;
return new SecurityStatusPal(errorCode);
}
catch (Exception ex)
{
if (NetEventSource.IsEnabled) NetEventSource.Error(null, ex);
return new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex);
}
}