internal unsafe static int ApplyControlToken(
ref SafeDeleteContext refContext,
SecurityBuffer[] inSecBuffers)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Enter(null);
NetEventSource.Info(null, $" refContext = {refContext}");
NetEventSource.Info(null, $" inSecBuffers[] = length:{inSecBuffers.Length}");
}
if (inSecBuffers == null)
{
NetEventSource.Fail(null, "inSecBuffers == null");
}
var inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length);
int errorCode = (int)Interop.SECURITY_STATUS.InvalidHandle;
// These are pinned user byte arrays passed along with SecurityBuffers.
GCHandle[] pinnedInBytes = null;
var inUnmanagedBuffer = new Interop.SspiCli.SecBuffer[inSecurityBufferDescriptor.cBuffers];
fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
{
// Fix Descriptor pointer that points to unmanaged SecurityBuffers.
inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr;
pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.cBuffers];
SecurityBuffer securityBuffer;
for (int index = 0; index < inSecurityBufferDescriptor.cBuffers; ++index)
{
securityBuffer = inSecBuffers[index];
if (securityBuffer != null)
{
inUnmanagedBuffer[index].cbBuffer = securityBuffer.size;
inUnmanagedBuffer[index].BufferType = securityBuffer.type;
// Use the unmanaged token if it's not null; otherwise use the managed buffer.
if (securityBuffer.unmanagedToken != null)
{
inUnmanagedBuffer[index].pvBuffer = securityBuffer.unmanagedToken.DangerousGetHandle();
}
else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
{
inUnmanagedBuffer[index].pvBuffer = IntPtr.Zero;
}
else
{
pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
inUnmanagedBuffer[index].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
}
#if TRACE_VERBOSE
if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"SecBuffer: cbBuffer:{securityBuffer.size} BufferType:{securityBuffer.type}");
#endif
}
}
// TODO: (#3114): Optimizations to remove the unnecesary allocation of a CredHandle, remove the AddRef
// if refContext was previously null, refactor the code to unify CompleteAuthToken and ApplyControlToken.
Interop.SspiCli.CredHandle contextHandle = new Interop.SspiCli.CredHandle();
if (refContext != null)
{
contextHandle = refContext._handle;
}
try
{
if (refContext == null || refContext.IsInvalid)
{
refContext = new SafeDeleteContext_SECURITY();
}
try
{
bool ignore = false;
refContext.DangerousAddRef(ref ignore);
errorCode = Interop.SspiCli.ApplyControlToken(contextHandle.IsZero ? null : &contextHandle, ref inSecurityBufferDescriptor);
}
finally
{
refContext.DangerousRelease();
}
}
finally
{
if (pinnedInBytes != null)
{
for (int index = 0; index < pinnedInBytes.Length; index++)
{
if (pinnedInBytes[index].IsAllocated)
{
pinnedInBytes[index].Free();
}
}
}
}
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"unmanaged ApplyControlToken() errorCode:0x{errorCode:x8} refContext: {refContext}");
return errorCode;
}
}