//-------------------------------------------------------------------
        internal unsafe static int AcceptSecurityContext(
            ref SafeFreeCredentials inCredentials,
            ref SafeDeleteContext refContext,
            Interop.Secur32.ContextFlags inFlags,
            Interop.Secur32.Endianness endianness,
            SecurityBuffer inSecBuffer,
            SecurityBuffer[] inSecBuffers,
            SecurityBuffer outSecBuffer,
            ref Interop.Secur32.ContextFlags outFlags)
        {
#if TRACE_VERBOSE
            GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex");
            GlobalLog.Print("    credential       = " + inCredentials.ToString());
            GlobalLog.Print("    refContext       = " + Logging.ObjectToString(refContext));

            GlobalLog.Print("    inFlags          = " + inFlags);

            if (inSecBuffers == null)
            {
                GlobalLog.Print("    inSecBuffers     = (null)");
            }
            else
            {
                GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
            }
#endif
            GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null");
            GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null");

            if (inCredentials == null)
            {
                throw new ArgumentNullException("inCredentials");
            }

            Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null;
            if (inSecBuffer != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);
            }
            else if (inSecBuffers != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length);
            }

            Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);

            // Actually, this is returned in outFlags.
            bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false;

            int errorCode = -1;

            Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle();
            if (refContext != null)
            {
                contextHandle = refContext._handle;
            }

            // These are pinned user byte arrays passed along with SecurityBuffers.
            GCHandle[] pinnedInBytes = null;
            GCHandle pinnedOutBytes = new GCHandle();

            // Optional output buffer that may need to be freed.
            SafeFreeContextBuffer outFreeContextBuffer = null;
            try
            {
                pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned);
                var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count];
                fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
                {
                    if (inSecurityBufferDescriptor != null)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr;
                        pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count];
                        SecurityBuffer securityBuffer;
                        for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index)
                        {
                            securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index];
                            if (securityBuffer != null)
                            {
                                // Copy the SecurityBuffer content into unmanaged place holder.
                                inUnmanagedBuffer[index].count = securityBuffer.size;
                                inUnmanagedBuffer[index].type = securityBuffer.type;

                                // Use the unmanaged token if it's not null; otherwise use the managed buffer.
                                if (securityBuffer.unmanagedToken != null)
                                {
                                    inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle();
                                }
                                else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
                                {
                                    inUnmanagedBuffer[index].token = IntPtr.Zero;
                                }
                                else
                                {
                                    pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
                                    inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
                                }
#if TRACE_VERBOSE
                                GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type);
#endif
                            }
                        }
                    }

                    var outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1];
                    fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr;
                        // Copy the SecurityBuffer content into unmanaged place holder.
                        outUnmanagedBuffer[0].count = outSecBuffer.size;
                        outUnmanagedBuffer[0].type = outSecBuffer.type;

                        if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
                        {
                            outUnmanagedBuffer[0].token = IntPtr.Zero;
                        }
                        else
                        {
                            outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
                        }

                        if (isSspiAllocated)
                        {
                            outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
                        }

                        if (refContext == null || refContext.IsInvalid)
                        {
                            refContext = new SafeDeleteContext_SECURITY();
                        }

                        errorCode = MustRunAcceptSecurityContext_SECURITY(
                                        ref inCredentials,
                                        contextHandle.IsZero ? null : &contextHandle,
                                        inSecurityBufferDescriptor,
                                        inFlags,
                                        endianness,
                                        refContext,
                                        outSecurityBufferDescriptor,
                                        ref outFlags,
                                        outFreeContextBuffer);

                        GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext  Marshalling OUT buffer");
                        // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
                        outSecBuffer.size = outUnmanagedBuffer[0].count;
                        outSecBuffer.type = outUnmanagedBuffer[0].type;
                        if (outSecBuffer.size > 0)
                        {
                            outSecBuffer.token = new byte[outSecBuffer.size];
                            Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size);
                        }
                        else
                        {
                            outSecBuffer.token = null;
                        }
                    }
                }
            }
            finally
            {
                if (pinnedInBytes != null)
                {
                    for (int index = 0; index < pinnedInBytes.Length; index++)
                    {
                        if (pinnedInBytes[index].IsAllocated)
                        {
                            pinnedInBytes[index].Free();
                        }
                    }
                }

                if (pinnedOutBytes.IsAllocated)
                {
                    pinnedOutBytes.Free();
                }

                if (outFreeContextBuffer != null)
                {
                    outFreeContextBuffer.Dispose();
                }
            }

            GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext));

            return errorCode;
        }
        internal unsafe static int CompleteAuthToken(
            ref SafeDeleteContext refContext,
            SecurityBuffer[] inSecBuffers)
        {
            GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken");
            GlobalLog.Print("    refContext       = " + Logging.ObjectToString(refContext));
#if TRACE_VERBOSE
            GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
#endif
            GlobalLog.Assert(inSecBuffers != null, "SafeDeleteContext::CompleteAuthToken()|inSecBuffers == null");
            var inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length);

            int errorCode = (int)Interop.SecurityStatus.InvalidHandle;

            // These are pinned user byte arrays passed along with SecurityBuffers.
            GCHandle[] pinnedInBytes = null;

            var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor.Count];
            fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
            {
                // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr;
                pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count];
                SecurityBuffer securityBuffer;
                for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index)
                {
                    securityBuffer = inSecBuffers[index];
                    if (securityBuffer != null)
                    {
                        inUnmanagedBuffer[index].count = securityBuffer.size;
                        inUnmanagedBuffer[index].type = securityBuffer.type;

                        // Use the unmanaged token if it's not null; otherwise use the managed buffer.
                        if (securityBuffer.unmanagedToken != null)
                        {
                            inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle();
                        }
                        else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
                        {
                            inUnmanagedBuffer[index].token = IntPtr.Zero;
                        }
                        else
                        {
                            pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
                            inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
                        }
#if TRACE_VERBOSE
                        GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type);
#endif
                    }
                }

                Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle();
                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.Secur32.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor);
                    }
                    finally
                    {
                        refContext.DangerousRelease();
                    }
                }
                finally
                {
                    if (pinnedInBytes != null)
                    {
                        for (int index = 0; index < pinnedInBytes.Length; index++)
                        {
                            if (pinnedInBytes[index].IsAllocated)
                            {
                                pinnedInBytes[index].Free();
                            }
                        }
                    }
                }
            }

            GlobalLog.Leave("SafeDeleteContext::CompleteAuthToken() unmanaged CompleteAuthToken()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext));

            return errorCode;
        }
示例#3
0
        //-------------------------------------------------------------------
        internal unsafe static int AcceptSecurityContext(
            ref SafeFreeCredentials inCredentials,
            ref SafeDeleteContext refContext,
            Interop.SspiCli.ContextFlags inFlags,
            Interop.SspiCli.Endianness endianness,
            SecurityBuffer inSecBuffer,
            SecurityBuffer[] inSecBuffers,
            SecurityBuffer outSecBuffer,
            ref Interop.SspiCli.ContextFlags outFlags)
        {
#if TRACE_VERBOSE
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(null, $"credential={inCredentials}, refContext={refContext}, inFlags={inFlags}");
                if (inSecBuffers == null)
                {
                    NetEventSource.Info(null, "inSecBuffers = (null)");
                }
                else
                {
                    NetEventSource.Info(null, $"inSecBuffers[] = (inSecBuffers)");
                }
            }
#endif

            if (outSecBuffer == null)
            {
                NetEventSource.Fail(null, "outSecBuffer != null");
            }
            if (inSecBuffer != null && inSecBuffers != null)
            {
                NetEventSource.Fail(null, "inSecBuffer == null || inSecBuffers == null");
            }

            if (inCredentials == null)
            {
                throw new ArgumentNullException(nameof(inCredentials));
            }

            Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = default(Interop.SspiCli.SecBufferDesc);
            bool haveInSecurityBufferDescriptor = false;
            if (inSecBuffer != null)
            {
                inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1);
                haveInSecurityBufferDescriptor = true;
            }
            else if (inSecBuffers != null)
            {
                inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Length);
                haveInSecurityBufferDescriptor = true;
            }

            Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(1);

            // Actually, this is returned in outFlags.
            bool isSspiAllocated = (inFlags & Interop.SspiCli.ContextFlags.AllocateMemory) != 0 ? true : false;

            int errorCode = -1;

            Interop.SspiCli.CredHandle contextHandle = new Interop.SspiCli.CredHandle();
            if (refContext != null)
            {
                contextHandle = refContext._handle;
            }

            // These are pinned user byte arrays passed along with SecurityBuffers.
            GCHandle[] pinnedInBytes = null;
            GCHandle pinnedOutBytes = new GCHandle();

            // Optional output buffer that may need to be freed.
            SafeFreeContextBuffer outFreeContextBuffer = null;
            try
            {
                pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned);
                var inUnmanagedBuffer = new Interop.SspiCli.SecBuffer[haveInSecurityBufferDescriptor ? inSecurityBufferDescriptor.cBuffers : 1];
                fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer)
                {
                    if (haveInSecurityBufferDescriptor)
                    {
                        // 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 = inSecBuffer != null ? inSecBuffer : inSecBuffers[index];
                            if (securityBuffer != null)
                            {
                                // Copy the SecurityBuffer content into unmanaged place holder.
                                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
                            }
                        }
                    }

                    var outUnmanagedBuffer = new Interop.SspiCli.SecBuffer[1];
                    fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        outSecurityBufferDescriptor.pBuffers = outUnmanagedBufferPtr;
                        // Copy the SecurityBuffer content into unmanaged place holder.
                        outUnmanagedBuffer[0].cbBuffer = outSecBuffer.size;
                        outUnmanagedBuffer[0].BufferType = outSecBuffer.type;

                        if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
                        {
                            outUnmanagedBuffer[0].pvBuffer = IntPtr.Zero;
                        }
                        else
                        {
                            outUnmanagedBuffer[0].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
                        }

                        if (isSspiAllocated)
                        {
                            outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
                        }

                        if (refContext == null || refContext.IsInvalid)
                        {
                            refContext = new SafeDeleteContext_SECURITY();
                        }

                        errorCode = MustRunAcceptSecurityContext_SECURITY(
                                        ref inCredentials,
                                        contextHandle.IsZero ? null : &contextHandle,
                                        haveInSecurityBufferDescriptor ? &inSecurityBufferDescriptor : null,
                                        inFlags,
                                        endianness,
                                        refContext,
                                        ref outSecurityBufferDescriptor,
                                        ref outFlags,
                                        outFreeContextBuffer);

                        if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Marshaling OUT buffer");
                        
                        // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
                        outSecBuffer.size = outUnmanagedBuffer[0].cbBuffer;
                        outSecBuffer.type = outUnmanagedBuffer[0].BufferType;
                        if (outSecBuffer.size > 0)
                        {
                            outSecBuffer.token = new byte[outSecBuffer.size];
                            Marshal.Copy(outUnmanagedBuffer[0].pvBuffer, outSecBuffer.token, 0, outSecBuffer.size);
                        }
                        else
                        {
                            outSecBuffer.token = null;
                        }
                    }
                }
            }
            finally
            {
                if (pinnedInBytes != null)
                {
                    for (int index = 0; index < pinnedInBytes.Length; index++)
                    {
                        if (pinnedInBytes[index].IsAllocated)
                        {
                            pinnedInBytes[index].Free();
                        }
                    }
                }

                if (pinnedOutBytes.IsAllocated)
                {
                    pinnedOutBytes.Free();
                }

                if (outFreeContextBuffer != null)
                {
                    outFreeContextBuffer.Dispose();
                }
            }

            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}");
            return errorCode;
        }
示例#4
0
        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;
        }
        //-------------------------------------------------------------------
        internal unsafe static int AcceptSecurityContext(
            ref SafeFreeCredentials inCredentials,
            ref SafeDeleteContext refContext,
            Interop.Secur32.ContextFlags inFlags,
            Interop.Secur32.Endianness endianness,
            SecurityBuffer inSecBuffer,
            SecurityBuffer[] inSecBuffers,
            SecurityBuffer outSecBuffer,
            ref Interop.Secur32.ContextFlags outFlags)
        {
#if TRACE_VERBOSE
            GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex");
            GlobalLog.Print("    credential       = " + inCredentials.ToString());
            GlobalLog.Print("    refContext       = " + Logging.ObjectToString(refContext));

            GlobalLog.Print("    inFlags          = " + inFlags);

            if (inSecBuffers == null)
            {
                GlobalLog.Print("    inSecBuffers     = (null)");
            }
            else
            {
                GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
            }
#endif
            GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null");
            GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null");

            if (inCredentials == null)
            {
                throw new ArgumentNullException("inCredentials");
            }

            Interop.Secur32.SecurityBufferDescriptor inSecurityBufferDescriptor = null;
            if (inSecBuffer != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);
            }
            else if (inSecBuffers != null)
            {
                inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length);
            }

            Interop.Secur32.SecurityBufferDescriptor outSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(1);

            // Actually, this is returned in outFlags.
            bool isSspiAllocated = (inFlags & Interop.Secur32.ContextFlags.AllocateMemory) != 0 ? true : false;

            int errorCode = -1;

            Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle();
            if (refContext != null)
            {
                contextHandle = refContext._handle;
            }

            // These are pinned user byte arrays passed along with SecurityBuffers.
            GCHandle[] pinnedInBytes  = null;
            GCHandle   pinnedOutBytes = new GCHandle();

            // Optional output buffer that may need to be freed.
            SafeFreeContextBuffer outFreeContextBuffer = null;
            try
            {
                pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned);
                var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count];
                fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer)
                {
                    if (inSecurityBufferDescriptor != null)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr;
                        pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count];
                        SecurityBuffer securityBuffer;
                        for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index)
                        {
                            securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index];
                            if (securityBuffer != null)
                            {
                                // Copy the SecurityBuffer content into unmanaged place holder.
                                inUnmanagedBuffer[index].count = securityBuffer.size;
                                inUnmanagedBuffer[index].type  = securityBuffer.type;

                                // Use the unmanaged token if it's not null; otherwise use the managed buffer.
                                if (securityBuffer.unmanagedToken != null)
                                {
                                    inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle();
                                }
                                else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
                                {
                                    inUnmanagedBuffer[index].token = IntPtr.Zero;
                                }
                                else
                                {
                                    pinnedInBytes[index]           = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
                                    inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
                                }
#if TRACE_VERBOSE
                                GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type);
#endif
                            }
                        }
                    }

                    var outUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[1];
                    fixed(void *outUnmanagedBufferPtr = outUnmanagedBuffer)
                    {
                        // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                        outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr;
                        // Copy the SecurityBuffer content into unmanaged place holder.
                        outUnmanagedBuffer[0].count = outSecBuffer.size;
                        outUnmanagedBuffer[0].type  = outSecBuffer.type;

                        if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
                        {
                            outUnmanagedBuffer[0].token = IntPtr.Zero;
                        }
                        else
                        {
                            outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
                        }

                        if (isSspiAllocated)
                        {
                            outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
                        }

                        if (refContext == null || refContext.IsInvalid)
                        {
                            refContext = new SafeDeleteContext_SECURITY();
                        }

                        errorCode = MustRunAcceptSecurityContext_SECURITY(
                            ref inCredentials,
                            contextHandle.IsZero ? null : &contextHandle,
                            inSecurityBufferDescriptor,
                            inFlags,
                            endianness,
                            refContext,
                            outSecurityBufferDescriptor,
                            ref outFlags,
                            outFreeContextBuffer);

                        GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext  Marshalling OUT buffer");
                        // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
                        outSecBuffer.size = outUnmanagedBuffer[0].count;
                        outSecBuffer.type = outUnmanagedBuffer[0].type;
                        if (outSecBuffer.size > 0)
                        {
                            outSecBuffer.token = new byte[outSecBuffer.size];
                            Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size);
                        }
                        else
                        {
                            outSecBuffer.token = null;
                        }
                    }
                }
            }
            finally
            {
                if (pinnedInBytes != null)
                {
                    for (int index = 0; index < pinnedInBytes.Length; index++)
                    {
                        if (pinnedInBytes[index].IsAllocated)
                        {
                            pinnedInBytes[index].Free();
                        }
                    }
                }

                if (pinnedOutBytes.IsAllocated)
                {
                    pinnedOutBytes.Free();
                }

                if (outFreeContextBuffer != null)
                {
                    outFreeContextBuffer.Dispose();
                }
            }

            GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext));

            return(errorCode);
        }
        internal unsafe static int CompleteAuthToken(
            ref SafeDeleteContext refContext,
            SecurityBuffer[] inSecBuffers)
        {
            GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken");
            GlobalLog.Print("    refContext       = " + Logging.ObjectToString(refContext));
#if TRACE_VERBOSE
            GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
#endif
            GlobalLog.Assert(inSecBuffers != null, "SafeDeleteContext::CompleteAuthToken()|inSecBuffers == null");
            var inSecurityBufferDescriptor = new Interop.Secur32.SecurityBufferDescriptor(inSecBuffers.Length);

            int errorCode = (int)Interop.SecurityStatus.InvalidHandle;

            // These are pinned user byte arrays passed along with SecurityBuffers.
            GCHandle[] pinnedInBytes = null;

            var inUnmanagedBuffer = new Interop.Secur32.SecurityBufferStruct[inSecurityBufferDescriptor.Count];
            fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer)
            {
                // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
                inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr;
                pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count];
                SecurityBuffer securityBuffer;

                for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index)
                {
                    securityBuffer = inSecBuffers[index];
                    if (securityBuffer != null)
                    {
                        inUnmanagedBuffer[index].count = securityBuffer.size;
                        inUnmanagedBuffer[index].type  = securityBuffer.type;

                        // Use the unmanaged token if it's not null; otherwise use the managed buffer.
                        if (securityBuffer.unmanagedToken != null)
                        {
                            inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle();
                        }
                        else if (securityBuffer.token == null || securityBuffer.token.Length == 0)
                        {
                            inUnmanagedBuffer[index].token = IntPtr.Zero;
                        }
                        else
                        {
                            pinnedInBytes[index]           = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned);
                            inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset);
                        }
#if TRACE_VERBOSE
                        GlobalLog.Print("SecBuffer: cbBuffer:" + securityBuffer.size + " BufferType:" + securityBuffer.type);
#endif
                    }
                }

                Interop.Secur32.SSPIHandle contextHandle = new Interop.Secur32.SSPIHandle();
                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.Secur32.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor);
                    }
                    finally
                    {
                        refContext.DangerousRelease();
                    }
                }
                finally
                {
                    if (pinnedInBytes != null)
                    {
                        for (int index = 0; index < pinnedInBytes.Length; index++)
                        {
                            if (pinnedInBytes[index].IsAllocated)
                            {
                                pinnedInBytes[index].Free();
                            }
                        }
                    }
                }
            }

            GlobalLog.Leave("SafeDeleteContext::CompleteAuthToken() unmanaged CompleteAuthToken()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + Logging.ObjectToString(refContext));

            return(errorCode);
        }