internal static unsafe int AcceptSecurityContext( ref SafeFreeCredentials?inCredentials, ref SafeDeleteSslContext?refContext, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inSecBuffers, ref SecurityBuffer outSecBuffer, ref Interop.SspiCli.ContextFlags outFlags) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(null, $"credential={inCredentials}, refContext={refContext}, inFlags={inFlags}"); } if (inCredentials == null) { throw new ArgumentNullException(nameof(inCredentials)); } Debug.Assert(inSecBuffers.Count <= 3); Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Count); Interop.SspiCli.SecBufferDesc outSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(count: 2); // Actually, this is returned in outFlags. bool isSspiAllocated = (inFlags & Interop.SspiCli.ContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; bool isContextAbsent = true; if (refContext != null) { isContextAbsent = refContext._handle.IsZero; } // Optional output buffer that may need to be freed. SafeFreeContextBuffer? outFreeContextBuffer = null; Span <Interop.SspiCli.SecBuffer> outUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[2]; outUnmanagedBuffer[1].pvBuffer = IntPtr.Zero; try { // Allocate always maximum to allow better code optimization. Span <Interop.SspiCli.SecBuffer> inUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[3]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) fixed(void *outUnmanagedBufferPtr = outUnmanagedBuffer) fixed(void *pinnedToken0 = inSecBuffers._item0.Token) fixed(void *pinnedToken1 = inSecBuffers._item1.Token) fixed(void *pinnedToken2 = inSecBuffers._item2.Token) { inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr; // Updated pvBuffer with pinned address. UnmanagedToken takes precedence. if (inSecBuffers.Count > 2) { inUnmanagedBuffer[2].BufferType = inSecBuffers._item2.Type; inUnmanagedBuffer[2].cbBuffer = inSecBuffers._item2.Token.Length; inUnmanagedBuffer[2].pvBuffer = inSecBuffers._item2.UnmanagedToken != null ? (IntPtr)inSecBuffers._item2.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken2; } if (inSecBuffers.Count > 1) { inUnmanagedBuffer[1].BufferType = inSecBuffers._item1.Type; inUnmanagedBuffer[1].cbBuffer = inSecBuffers._item1.Token.Length; inUnmanagedBuffer[1].pvBuffer = inSecBuffers._item1.UnmanagedToken != null ? (IntPtr)inSecBuffers._item1.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken1; } if (inSecBuffers.Count > 0) { inUnmanagedBuffer[0].BufferType = inSecBuffers._item0.Type; inUnmanagedBuffer[0].cbBuffer = inSecBuffers._item0.Token.Length; inUnmanagedBuffer[0].pvBuffer = inSecBuffers._item0.UnmanagedToken != null ? (IntPtr)inSecBuffers._item0.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken0; } fixed(byte *pinnedOutBytes = outSecBuffer.token) { // 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; outUnmanagedBuffer[0].pvBuffer = outSecBuffer.token == null || outSecBuffer.token.Length == 0 ? IntPtr.Zero : (IntPtr)(pinnedOutBytes + outSecBuffer.offset); outUnmanagedBuffer[1].cbBuffer = 0; outUnmanagedBuffer[1].BufferType = SecurityBufferType.SECBUFFER_ALERT; if (isSspiAllocated) { outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); } if (refContext == null || refContext.IsInvalid) { // Previous versions unconditionally built a new "refContext" here, but would pass // incorrect arguments to AcceptSecurityContext in cases where an "contextHandle" was // already present and non-zero. if (isContextAbsent) { refContext = new SafeDeleteSslContext(); } } errorCode = MustRunAcceptSecurityContext_SECURITY( ref inCredentials, isContextAbsent, &inSecurityBufferDescriptor, inFlags, endianness, refContext !, ref outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, "Marshaling OUT buffer"); } // No data written out but there is Alert if (outUnmanagedBuffer[0].cbBuffer == 0 && outUnmanagedBuffer[1].cbBuffer > 0) { outSecBuffer.size = outUnmanagedBuffer[1].cbBuffer; outSecBuffer.type = outUnmanagedBuffer[1].BufferType; outSecBuffer.token = new Span <byte>((byte *)outUnmanagedBuffer[1].pvBuffer, outUnmanagedBuffer[1].cbBuffer).ToArray(); } else { outSecBuffer.size = outUnmanagedBuffer[0].cbBuffer; outSecBuffer.type = outUnmanagedBuffer[0].BufferType; outSecBuffer.token = outUnmanagedBuffer[0].cbBuffer > 0 ? new Span <byte>((byte *)outUnmanagedBuffer[0].pvBuffer, outUnmanagedBuffer[0].cbBuffer).ToArray() : null; } } } } finally { outFreeContextBuffer?.Dispose(); if (outUnmanagedBuffer[1].pvBuffer != IntPtr.Zero) { Interop.SspiCli.FreeContextBuffer(outUnmanagedBuffer[1].pvBuffer); } } if (NetEventSource.IsEnabled) { NetEventSource.Exit(null, $"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 static unsafe int InitializeSecurityContext( ref SafeFreeCredentials?inCredentials, ref SafeDeleteSslContext?refContext, string?targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inSecBuffers, ref SecurityBuffer outSecBuffer, ref Interop.SspiCli.ContextFlags outFlags) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(null, $"credential:{inCredentials}, crefContext:{refContext}, targetName:{targetName}, inFlags:{inFlags}, endianness:{endianness}"); } if (inCredentials == null) { throw new ArgumentNullException(nameof(inCredentials)); } Debug.Assert(inSecBuffers.Count <= 3); Interop.SspiCli.SecBufferDesc inSecurityBufferDescriptor = new Interop.SspiCli.SecBufferDesc(inSecBuffers.Count); 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; bool isContextAbsent = true; if (refContext != null) { isContextAbsent = refContext._handle.IsZero; } // Optional output buffer that may need to be freed. SafeFreeContextBuffer?outFreeContextBuffer = null; try { Span <Interop.SspiCli.SecBuffer> inUnmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[3]; fixed(void *inUnmanagedBufferPtr = inUnmanagedBuffer) fixed(void *pinnedToken0 = inSecBuffers._item0.Token) fixed(void *pinnedToken1 = inSecBuffers._item1.Token) fixed(void *pinnedToken2 = inSecBuffers._item2.Token) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. inSecurityBufferDescriptor.pBuffers = inUnmanagedBufferPtr; // Updated pvBuffer with pinned address. UnmanagedToken takes precedence. if (inSecBuffers.Count > 2) { inUnmanagedBuffer[2].BufferType = inSecBuffers._item2.Type; inUnmanagedBuffer[2].cbBuffer = inSecBuffers._item2.Token.Length; inUnmanagedBuffer[2].pvBuffer = inSecBuffers._item2.UnmanagedToken != null ? (IntPtr)inSecBuffers._item2.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken2; } if (inSecBuffers.Count > 1) { inUnmanagedBuffer[1].BufferType = inSecBuffers._item1.Type; inUnmanagedBuffer[1].cbBuffer = inSecBuffers._item1.Token.Length; inUnmanagedBuffer[1].pvBuffer = inSecBuffers._item1.UnmanagedToken != null ? (IntPtr)inSecBuffers._item1.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken1; } if (inSecBuffers.Count > 0) { inUnmanagedBuffer[0].BufferType = inSecBuffers._item0.Type; inUnmanagedBuffer[0].cbBuffer = inSecBuffers._item0.Token.Length; inUnmanagedBuffer[0].pvBuffer = inSecBuffers._item0.UnmanagedToken != null ? (IntPtr)inSecBuffers._item0.UnmanagedToken.DangerousGetHandle() : (IntPtr)pinnedToken0; } fixed(byte *pinnedOutBytes = outSecBuffer.token) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers. Interop.SspiCli.SecBuffer outUnmanagedBuffer = default; outSecurityBufferDescriptor.pBuffers = &outUnmanagedBuffer; outUnmanagedBuffer.cbBuffer = outSecBuffer.size; outUnmanagedBuffer.BufferType = outSecBuffer.type; outUnmanagedBuffer.pvBuffer = outSecBuffer.token == null || outSecBuffer.token.Length == 0 ? IntPtr.Zero : (IntPtr)(pinnedOutBytes + outSecBuffer.offset); if (isSspiAllocated) { outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); } if (refContext == null || refContext.IsInvalid) { // Previous versions unconditionally built a new "refContext" here, but would pass // incorrect arguments to InitializeSecurityContextW in cases where an "contextHandle" was // already present and non-zero. if (isContextAbsent) { refContext = new SafeDeleteSslContext(); } } if (targetName == null || targetName.Length == 0) { targetName = dummyStr; } string punyCode = s_idnMapping.GetAscii(targetName); fixed(char *namePtr = punyCode) { errorCode = MustRunInitializeSecurityContext( ref inCredentials, isContextAbsent, (byte *)(((object)targetName == (object)dummyStr) ? null : namePtr), inFlags, endianness, &inSecurityBufferDescriptor, refContext !, ref outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer); } if (NetEventSource.IsEnabled) { NetEventSource.Info(null, "Marshalling OUT buffer"); } // Get unmanaged buffer with index 0 as the only one passed into PInvoke. outSecBuffer.size = outUnmanagedBuffer.cbBuffer; outSecBuffer.type = outUnmanagedBuffer.BufferType; outSecBuffer.token = outSecBuffer.size > 0 ? new Span <byte>((byte *)outUnmanagedBuffer.pvBuffer, outUnmanagedBuffer.cbBuffer).ToArray() : null; } } } finally { outFreeContextBuffer?.Dispose(); } if (NetEventSource.IsEnabled) { NetEventSource.Exit(null, $"errorCode:0x{errorCode:x8}, refContext:{refContext}"); } return(errorCode); }