Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / IdentityModel / System / IdentityModel / SspiSafeHandles.cs / 2 / SspiSafeHandles.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- /*++ Abstract: The file contains SafeHandles implementations for SSPI. These handle wrappers do guarantee that OS resources get cleaned up when the app domain dies. All PInvoke declarations that do freeing the OS resources _must_ be in this file All PInvoke declarations that do allocation the OS resources _must_ be in this file Details: The protection from leaking OF the OS resources is based on two technologies 1) SafeHandle class 2) Non interuptible regions using Constrained Execution Region (CER) technology For simple cases SafeHandle class does all the job. The Prerequisites are: - A resource is able to be represented by IntPtr type (32 bits on 32 bits platforms). - There is a PInvoke availble that does the creation of the resource. That PInvoke either returns the handle value or it writes the handle into out/ref parameter. - The above PInvoke as part of the call does NOT free any OS resource. For those "simple" cases we desinged SafeHandle-derived classes that provide static methods to allocate a handle object. Each such derived class provides a handle release method that is run as non-interrupted. For more complicated cases we employ the support for non-interruptible methods (CERs). Each CER is a tree of code rooted at a catch or finally clause for a specially marked exception handler (preceded by the RuntimeHelpers.PrepareConstrainedRegions() marker) or the Dispose or ReleaseHandle method of a SafeHandle derived class. The graph is automatically computed by the runtime (typically at the jit time of the root method), but cannot follow virtual or interface calls (these must be explicitly prepared via RuntimeHelpers.PrepareMethod once the definite target method is known). Also, methods in the graph that must be included in the CER must be marked with a reliability contract stating guarantees about the consistency of the system if an error occurs while they are executing. Look for ReliabilityContract for examples (a full explanation of the semantics of this contract is beyond the scope of this comment). An example of the top-level of a CER: RuntimeHelpers.PrepareConstrainedRegions(); try { // Normal code } finally { // Guaranteed to get here even in low memory scenarios. Thread abort will not interrupt // this clause and we won't fail because of a jit allocation of any method called (modulo // restrictions on interface/virtual calls listed above and further restrictions listed // below). } Another common pattern is an empty-try (where you really just want a region of code the runtime won't interrupt you in): RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { // Non-interruptible code here } This ugly syntax will be supplanted with compiler support at some point. While within a CER region certain restrictions apply in order to avoid having the runtime inject a potential fault point into your code (and of course you're are responsible for ensuring your code doesn't inject any explicit fault points of its own unless you know how to tolerate them). A quick and dirty guide to the possible causes of fault points in CER regions: - Explicit allocations (though allocating a value type only implies allocation on the stack, which may not present an issue). - Boxing a value type (C# does this implicitly for you in many cases, so be careful). - Use of Monitor.Enter or the lock keyword. - Accessing a multi-dimensional array. - Calling any method outside your control that doesn't make a guarantee (e.g. via a ReliabilityAttribute) that it doesn't introduce failure points. - Making P/Invoke calls with non-blittable parameters types. Blittable types are: - SafeHandle when used as an [in] parameter - NON BOXED base types that fit onto a machine word - ref struct with blittable fields - class type with blittable fields - pinned Unicode strings using "fixed" statement - pointers of any kind - IntPtr type - P/Invokes should not have any CharSet attribute on it's declaration. Obvioulsy string types should not appear in the parameters. - String type MUST not appear in a field of a marshaled ref struct or class in a P?Invoke (taken from the NCL classes) --*/ namespace System.IdentityModel { using System.Security; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Threading; using System.Security.Permissions; using System.ComponentModel; using System.Text; using System.ServiceModel.Diagnostics; using Microsoft.Win32.SafeHandles; using System.Runtime.ConstrainedExecution; [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct SSPIHandle { private IntPtr HandleHi; private IntPtr HandleLo; public bool IsZero { get {return HandleHi == IntPtr.Zero && HandleLo == IntPtr.Zero; } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal void SetToInvalid() { HandleHi = IntPtr.Zero; HandleLo = IntPtr.Zero; } //public static string ToString(ref SSPIHandle obj) //{ // return obj.HandleHi.ToString("x") + ":" + obj.HandleLo.ToString("x"); //} } internal class SafeDeleteContext : SafeHandle { private const string SECURITY = "security.Dll"; private const string dummyStr = " "; private static readonly byte[] dummyBytes = new byte[] {0}; internal SSPIHandle _handle; //should be always used as by ref in PINvokes parameters SafeFreeCredentials _EffectiveCredential; protected SafeDeleteContext() : base(IntPtr.Zero, true) { _handle = new SSPIHandle(); } public override bool IsInvalid { get { return IsClosed || _handle.IsZero; } } //This method should never be called for this type //public new IntPtr DangerousGetHandle() //{ // throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); //} //public static string ToString(SafeDeleteContext obj) //{ // { return obj == null ? "null" : SSPIHandle.ToString(ref obj._handle); } //} //------------------------------------------------------------------- internal static unsafe int InitializeSecurityContext( SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, string targetName, SspiContextFlags inFlags, Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, ref SspiContextFlags outFlags) { if (inCredentials == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("inCredentials"); } SecurityBufferDescriptor inSecurityBufferDescriptor = null; if (inSecBuffer != null) { inSecurityBufferDescriptor = new SecurityBufferDescriptor(1); } else if (inSecBuffers != null) { inSecurityBufferDescriptor = new SecurityBufferDescriptor(inSecBuffers.Length); } SecurityBufferDescriptor outSecurityBufferDescriptor = new SecurityBufferDescriptor(1); // actually this is returned in outFlags bool isSspiAllocated = (inFlags & SspiContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; SSPIHandle contextHandle = new 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); SecurityBufferStruct[] inUnmanagedBuffer = new 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; 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); } } } } SecurityBufferStruct[] outUnmanagedBuffer = new SecurityBufferStruct[1]; fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer) { // Fix Descriptor pointer that points to unmanaged SecurityBuffers outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; 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(); } if (targetName == null || targetName.Length == 0) { targetName = dummyStr; } fixed (char* namePtr = targetName) { errorCode = MustRunInitializeSecurityContext( inCredentials, contextHandle.IsZero ? null : &contextHandle, (byte*)(((object)targetName == (object)dummyStr) ? null : namePtr), inFlags, endianness, inSecurityBufferDescriptor, refContext, outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer ); } // 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 = DiagnosticUtility.Utility.AllocateByteArray(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.Close(); } } return errorCode; } // // After PINvoke call the method will fix the handleTemplate.handle with the returned value. // The caller is responsible for creating a correct SafeFreeContextBuffer or null can be passed if no handle is returned. // // Since it has a CER, this method can't have any references to imports from DLLs that may not exist on the system. // private static unsafe int MustRunInitializeSecurityContext( SafeFreeCredentials inCredentials, void * inContextPtr, byte * targetName, SspiContextFlags inFlags, Endianness endianness, SecurityBufferDescriptor inputBuffer, SafeDeleteContext outContext, SecurityBufferDescriptor outputBuffer, ref SspiContextFlags attributes, SafeFreeContextBuffer handleTemplate) { int errorCode = -1; bool b1 = false; bool b2 = false; // Run the body of this method as a non-interruptible block. RuntimeHelpers.PrepareConstrainedRegions(); try { inCredentials.DangerousAddRef(ref b1); outContext.DangerousAddRef(ref b2); } catch (Exception e) { if (b1) { inCredentials.DangerousRelease(); b1 = false; } if (b2) { outContext.DangerousRelease(); b2 = false; } if (!(e is ObjectDisposedException)) throw; } finally { long timeStamp; if (!b1) { // caller should retry inCredentials = null; } else if (b1 && b2) { SSPIHandle credentialHandle = inCredentials._handle; // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // This API does not set Win32 Last Error. errorCode = InitializeSecurityContextW( ref credentialHandle, inContextPtr, targetName, inFlags, 0, endianness, inputBuffer, 0, ref outContext._handle, outputBuffer, ref attributes, out timeStamp ); // // When a credential handle is first associated with the context we keep credential // ref count bumped up to ensure ordered finalization. // If the credential handle has been changed we de-ref the old one and associate the // context with the new cred handle but only if the call was successful. if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) { // Disassociate the previous credential handle if (outContext._EffectiveCredential != null) outContext._EffectiveCredential.DangerousRelease(); outContext._EffectiveCredential = inCredentials; } else { inCredentials.DangerousRelease(); } outContext.DangerousRelease(); // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. if (handleTemplate != null) { handleTemplate.Set(((SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes if (handleTemplate.IsInvalid) { handleTemplate.SetHandleAsInvalid(); } } } if (inContextPtr == null && (errorCode & 0x80000000) != 0) { // an error on the first call, need to set the out handle to invalid value outContext._handle.SetToInvalid(); } } return errorCode; } //------------------------------------------------------------------- internal static unsafe int AcceptSecurityContext( SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, SspiContextFlags inFlags, Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, ref SspiContextFlags outFlags) { if (inCredentials == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("inCredentials"); } SecurityBufferDescriptor inSecurityBufferDescriptor = null; if (inSecBuffer != null) { inSecurityBufferDescriptor = new SecurityBufferDescriptor(1); } else if (inSecBuffers != null) { inSecurityBufferDescriptor = new SecurityBufferDescriptor(inSecBuffers.Length); } SecurityBufferDescriptor outSecurityBufferDescriptor = new SecurityBufferDescriptor(1); // actually this is returned in outFlags bool isSspiAllocated = (inFlags & SspiContextFlags.AllocateMemory) != 0 ? true : false; int errorCode = -1; SSPIHandle contextHandle = new 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); SecurityBufferStruct[] inUnmanagedBuffer = new 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; 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); } } } } SecurityBufferStruct[] outUnmanagedBuffer = new 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(); } errorCode = MustRunAcceptSecurityContext( inCredentials, contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor, inFlags, endianness, refContext, outSecurityBufferDescriptor, ref outFlags, outFreeContextBuffer ); // 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 = DiagnosticUtility.Utility.AllocateByteArray(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.Close(); } } return errorCode; } // After PINvoke call the method will fix the handleTemplate.handle with the returned value. // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. // This method is run as non-interruptible. private static unsafe int MustRunAcceptSecurityContext( SafeFreeCredentials inCredentials, void* inContextPtr, SecurityBufferDescriptor inputBuffer, SspiContextFlags inFlags, Endianness endianness, SafeDeleteContext outContext, SecurityBufferDescriptor outputBuffer, ref SspiContextFlags outFlags, SafeFreeContextBuffer handleTemplate) { int errorCode = -1; bool b1 = false; bool b2 = false; // Run the body of this method as a non-interruptible block. RuntimeHelpers.PrepareConstrainedRegions(); try { inCredentials.DangerousAddRef(ref b1); outContext.DangerousAddRef(ref b2); } catch (Exception e) { if (b1) { inCredentials.DangerousRelease(); b1 = false; } if (b2) { outContext.DangerousRelease(); b2 = false; } if (!(e is ObjectDisposedException)) throw; } finally { long timeStamp; if (!b1) { // caller should retry inCredentials = null; } else if (b1 && b2) { SSPIHandle credentialHandle = inCredentials._handle; // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // This API does not set Win32 Last Error. errorCode = AcceptSecurityContext( ref credentialHandle, inContextPtr, inputBuffer, inFlags, endianness, ref outContext._handle, outputBuffer, ref outFlags, out timeStamp ); // // When a credential handle is first associated with the context we keep credential // ref count bumped up to ensure ordered finalization. // If the credential handle has been changed we de-ref the old one and associate the // context with the new cred handle but only if the call was successful. if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) { // Disassociate the previous credential handle if (outContext._EffectiveCredential != null) outContext._EffectiveCredential.DangerousRelease(); outContext._EffectiveCredential = inCredentials; } else { inCredentials.DangerousRelease(); } outContext.DangerousRelease(); // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. if (handleTemplate != null) { handleTemplate.Set(((SecurityBufferStruct * ) outputBuffer.UnmanagedPointer)->token); //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes if (handleTemplate.IsInvalid) { handleTemplate.SetHandleAsInvalid(); } } if (inContextPtr == null && (errorCode & 0x80000000) != 0) { // an error on the first call, need to set the out handle to invalid value outContext._handle.SetToInvalid(); } } } return errorCode; } public static int ImpersonateSecurityContext(SafeDeleteContext context) { int status = (int)SecurityStatus.InvalidHandle; bool b = false; RuntimeHelpers.PrepareConstrainedRegions(); try { context.DangerousAddRef(ref b); } catch (Exception e) { if (b) { context.DangerousRelease(); b = false; } if (!(e is ObjectDisposedException)) throw; } finally { if (b) { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. It returns a error code. status = ImpersonateSecurityContext(ref context._handle); context.DangerousRelease(); } } return status; } public static int EncryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) { int status = (int)SecurityStatus.InvalidHandle; bool b = false; RuntimeHelpers.PrepareConstrainedRegions(); try { context.DangerousAddRef(ref b); } catch (Exception e) { if (b) { context.DangerousRelease(); b = false; } if (!(e is ObjectDisposedException)) throw; } finally { if (b) { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. It returns a error code. status = EncryptMessage(ref context._handle, 0, inputOutput, sequenceNumber); context.DangerousRelease(); } } return status; } public unsafe static int DecryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) { int status = (int)SecurityStatus.InvalidHandle; bool b = false; uint qop = 0; RuntimeHelpers.PrepareConstrainedRegions(); try { context.DangerousAddRef(ref b); } catch (Exception e) { if (b) { context.DangerousRelease(); b = false; } if (!(e is ObjectDisposedException)) throw; } finally { if (b) { #pragma warning suppress 56523 // we don't take any action on the win32 error message. status = DecryptMessage(ref context._handle, inputOutput, sequenceNumber, &qop); context.DangerousRelease(); } } const uint SECQOP_WRAP_NO_ENCRYPT = 0x80000001; if (status == 0 && qop == SECQOP_WRAP_NO_ENCRYPT) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SspiPayloadNotEncrypted))); } return status; } internal int GetSecurityContextToken(out SafeCloseHandle safeHandle) { int status = (int) SecurityStatus.InvalidHandle; bool b = false; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref b); } catch (Exception e) { if (b) { DangerousRelease(); b = false; } if (!(e is ObjectDisposedException)) throw; } finally { if (b) { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. The API returns a error code. status = QuerySecurityContextToken(ref _handle, out safeHandle); DangerousRelease(); } else { safeHandle = new SafeCloseHandle(IntPtr.Zero, false); } } return status; } protected override bool ReleaseHandle() { if (this._EffectiveCredential != null) this._EffectiveCredential.DangerousRelease(); // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. It returns a error code. return DeleteSecurityContext(ref _handle) == 0; } [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private extern static int QuerySecurityContextToken(ref SSPIHandle phContext, [Out] out SafeCloseHandle handle); [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] internal extern static unsafe int InitializeSecurityContextW( ref SSPIHandle credentialHandle, [In] void * inContextPtr, [In] byte * targetName, [In] SspiContextFlags inFlags, [In] int reservedI, [In] Endianness endianness, [In] SecurityBufferDescriptor inputBuffer, [In] int reservedII, ref SSPIHandle outContextPtr, [In, Out] SecurityBufferDescriptor outputBuffer, [In, Out] ref SspiContextFlags attributes, out long timestamp ); [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] internal extern static unsafe int AcceptSecurityContext( ref SSPIHandle credentialHandle, [In] void * inContextPtr, [In] SecurityBufferDescriptor inputBuffer, [In] SspiContextFlags inFlags, [In] Endianness endianness, ref SSPIHandle outContextPtr, [In, Out] SecurityBufferDescriptor outputBuffer, [In, Out] ref SspiContextFlags attributes, out long timestamp ); [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] [SuppressUnmanagedCodeSecurity] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal extern static int DeleteSecurityContext( ref SSPIHandle handlePtr ); [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] internal extern static int ImpersonateSecurityContext( ref SSPIHandle handlePtr ); [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] internal extern static int EncryptMessage( ref SSPIHandle contextHandle, [In] uint qualityOfProtection, [In, Out] SecurityBufferDescriptor inputOutput, [In] uint sequenceNumber ); [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] internal unsafe extern static int DecryptMessage( ref SSPIHandle contextHandle, [In, Out] SecurityBufferDescriptor inputOutput, [In] uint sequenceNumber, uint* qualityOfProtection ); } internal class SafeFreeCredentials : SafeHandle { private const string SECURITY = "security.Dll"; internal SSPIHandle _handle; //should be always used as by ref in PINvokes parameters protected SafeFreeCredentials() : base(IntPtr.Zero, true) { _handle = new SSPIHandle(); } //internal static string ToString(SafeFreeCredentials obj) //{ return obj == null ? "null" : SSPIHandle.ToString(ref obj._handle); } public override bool IsInvalid { get { return IsClosed || _handle.IsZero; } } //This method should never be called for this type //public new IntPtr DangerousGetHandle() //{ // throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); //} public static unsafe int AcquireCredentialsHandle( string package, CredentialUse intent, ref AuthIdentityEx authdata, out SafeFreeCredentials outCredential) { int errorCode = -1; long timeStamp; outCredential = new SafeFreeCredentials(); RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. It returns a error code. errorCode = AcquireCredentialsHandleW( null, package, (int)intent, null, ref authdata, null, null, ref outCredential._handle, out timeStamp ); if (errorCode != 0) { outCredential.SetHandleAsInvalid(); } } return errorCode; } public static unsafe int AcquireDefaultCredential( string package, CredentialUse intent, ref AuthIdentityEx authIdentity, out SafeFreeCredentials outCredential) { int errorCode = -1; long timeStamp; outCredential = new SafeFreeCredentials(); RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. It returns a error code. errorCode = AcquireCredentialsHandleW( null, package, (int)intent, null, ref authIdentity, // IntPtr.Zero, null, null, ref outCredential._handle, out timeStamp ); if (errorCode != 0) { outCredential.SetHandleAsInvalid(); } } return errorCode; } public static unsafe int AcquireCredentialsHandle( string package, CredentialUse intent, ref SecureCredential authdata, out SafeFreeCredentials outCredential ) { int errorCode = -1; long timeStamp; // If there is a certificate, wrap it into an array IntPtr copiedPtr = authdata.certContextArray; try { IntPtr certArrayPtr = new IntPtr( & copiedPtr); if (copiedPtr != IntPtr.Zero) { authdata.certContextArray = certArrayPtr; } outCredential = new SafeFreeCredentials(); RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. It returns a error code. errorCode = AcquireCredentialsHandleW( null, package, (int)intent, null, ref authdata, null, null, ref outCredential._handle, out timeStamp ); if (errorCode != 0) { outCredential.SetHandleAsInvalid(); } } } finally { authdata.certContextArray = copiedPtr; } return errorCode; } protected override bool ReleaseHandle() { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. It returns a error code. return FreeCredentialsHandle(ref _handle) == 0; } [DllImport(SECURITY, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] internal extern static unsafe int AcquireCredentialsHandleW( [In] string principal, [In] string moduleName, [In] int usage, [In] void * logonID, [In] ref AuthIdentityEx authdata, [In] void * keyCallback, [In] void * keyArgument, ref SSPIHandle handlePtr, [Out] out long timeStamp ); [DllImport(SECURITY, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] internal extern static unsafe int AcquireCredentialsHandleW( [In] string principal, [In] string moduleName, [In] int usage, [In] void * logonID, [In] IntPtr zero, [In] void * keyCallback, [In] void * keyArgument, ref SSPIHandle handlePtr, [Out] out long timeStamp ); [DllImport(SECURITY, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] internal extern static unsafe int AcquireCredentialsHandleW( [In] string principal, [In] string moduleName, [In] int usage, [In] void * logonID, [In] ref SecureCredential authData, [In] void * keyCallback, [In] void * keyArgument, ref SSPIHandle handlePtr, [Out] out long timeStamp ); [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] [SuppressUnmanagedCodeSecurity] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal extern static int FreeCredentialsHandle( ref SSPIHandle handlePtr ); } internal sealed class SafeFreeCertContext : SafeHandleZeroOrMinusOneIsInvalid { const string CRYPT32 = "crypt32.dll"; const string ADVAPI32 = "advapi32.dll"; internal SafeFreeCertContext() : base(true) {} // This must be ONLY called from this file and form a MustRun method [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal unsafe void Set(IntPtr value) { this.handle = value; } const uint CRYPT_ACQUIRE_SILENT_FLAG = 0x00000040; [DllImport(CRYPT32, ExactSpelling = true, SetLastError = true)] [SuppressUnmanagedCodeSecurity] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private extern static bool CertFreeCertificateContext(// Suppressing returned status check, it's always==TRUE, [In] IntPtr certContext); protected override bool ReleaseHandle() { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. return CertFreeCertificateContext(handle); } } internal sealed class SafeFreeContextBuffer : SafeHandleZeroOrMinusOneIsInvalid { const string SECURITY = "security.dll"; SafeFreeContextBuffer() : base(true) {} // This must be ONLY called from this file and form a MustRun method [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal unsafe void Set(IntPtr value) { this.handle = value; } internal static int EnumeratePackages(out int pkgnum, out SafeFreeContextBuffer pkgArray) { int res = -1; // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. The API returns a error code. res = SafeFreeContextBuffer.EnumerateSecurityPackagesW(out pkgnum, out pkgArray); if (res != 0) { Utility.CloseInvalidOutSafeHandle(pkgArray); pkgArray = null; } return res; } internal static SafeFreeContextBuffer CreateEmptyHandle() { return new SafeFreeContextBuffer(); } // // After PInvoke call the method will fix the refHandle.handle with the returned value. // The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned. // // This method is run as non-interruptible. // public static unsafe int QueryContextAttributes(SafeDeleteContext phContext, ContextAttribute contextAttribute, byte * buffer, SafeHandle refHandle) { int status = (int)SecurityStatus.InvalidHandle; bool b = false; // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit // one of the following methods. So run within a CER non-interruptible block. RuntimeHelpers.PrepareConstrainedRegions(); try { phContext.DangerousAddRef(ref b); } catch (Exception e) { if (b) { phContext.DangerousRelease(); b = false; } if (!(e is ObjectDisposedException)) throw; } finally { if (b) { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. The API returns a error code. status = SafeFreeContextBuffer.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); phContext.DangerousRelease(); } if (status == 0 && refHandle != null) { if (refHandle is SafeFreeContextBuffer) { if (contextAttribute == ContextAttribute.SessionKey) { IntPtr keyPtr = Marshal.ReadIntPtr(new IntPtr(buffer), SecPkgContext_SessionKey.SessionkeyOffset); ((SafeFreeContextBuffer)refHandle).Set(keyPtr); } else { ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); } } else { ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); } } if (status != 0 && refHandle != null) { refHandle.SetHandleAsInvalid(); } } return status; } protected override bool ReleaseHandle() { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The API does not set Win32 Last Error. The API returns a error code. return FreeContextBuffer(handle) == 0; } [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] internal extern static unsafe int QueryContextAttributesW( ref SSPIHandle contextHandle, [In] ContextAttribute attribute, [In] void * buffer); [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] internal extern static int EnumerateSecurityPackagesW( [Out] out int pkgnum, [Out] out SafeFreeContextBuffer handle); [DllImport(SECURITY, ExactSpelling = true, SetLastError = true)] [SuppressUnmanagedCodeSecurity] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private extern static int FreeContextBuffer( [In] IntPtr contextBuffer); } internal sealed class SafeCloseHandle : SafeHandleZeroOrMinusOneIsInvalid { const string KERNEL32 = "kernel32.dll"; private SafeCloseHandle() : base(true) { } internal SafeCloseHandle(IntPtr handle, bool ownsHandle) : base(ownsHandle) { DiagnosticUtility.DebugAssert(handle == IntPtr.Zero || !ownsHandle, "Unsafe to create a SafeHandle that owns a pre-existing handle before the SafeHandle was created."); SetHandle(handle); } protected override bool ReleaseHandle() { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // We are not interested to throw an exception here. We can ignore the Last Error code. return CloseHandle(handle); } [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] [SuppressUnmanagedCodeSecurity] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private extern static bool CloseHandle(IntPtr handle); } [SecurityCritical(SecurityCriticalScope.Everything)] internal sealed class SafeCloseHandleCritical : SafeHandleZeroOrMinusOneIsInvalid { const string KERNEL32 = "kernel32.dll"; private SafeCloseHandleCritical() : base(true) { } protected override bool ReleaseHandle() { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // We are not interested to throw an exception here. We can ignore the Last Error code. return CloseHandle(handle); } [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] [SuppressUnmanagedCodeSecurity] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private extern static bool CloseHandle(IntPtr handle); } internal sealed class SafeHGlobalHandle : SafeHandleZeroOrMinusOneIsInvalid { SafeHGlobalHandle() : base(true) { } // 0 is an Invalid Handle SafeHGlobalHandle(IntPtr handle) : base(true) { DiagnosticUtility.DebugAssert(handle == IntPtr.Zero, "SafeHGlobalHandle constructor can only be called with IntPtr.Zero."); SetHandle(handle); } protected override bool ReleaseHandle() { Marshal.FreeHGlobal(handle); return true; } public static SafeHGlobalHandle InvalidHandle { get { return new SafeHGlobalHandle(IntPtr.Zero); } } public static SafeHGlobalHandle AllocHGlobal(string s) { byte[] bytes = DiagnosticUtility.Utility.AllocateByteArray(checked((s.Length + 1) * 2)); Encoding.Unicode.GetBytes(s, 0, s.Length, bytes, 0); return AllocHGlobal(bytes); } public static SafeHGlobalHandle AllocHGlobal(byte[] bytes) { SafeHGlobalHandle result = AllocHGlobal(bytes.Length); Marshal.Copy(bytes, 0, result.DangerousGetHandle(), bytes.Length); return result; } public static SafeHGlobalHandle AllocHGlobal(uint cb) { // The cast could overflow to minus. // Unfortunately, Marshal.AllocHGlobal only takes int. return AllocHGlobal((int)cb); } public static SafeHGlobalHandle AllocHGlobal(int cb) { if (cb < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("cb", SR.GetString(SR.ValueMustBeNonNegative))); } SafeHGlobalHandle result = new SafeHGlobalHandle(); // CER RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { IntPtr ptr = Marshal.AllocHGlobal(cb); result.SetHandle(ptr); } return result; } } internal sealed class SafeLsaLogonProcessHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeLsaLogonProcessHandle() : base(true) { } // 0 is an Invalid Handle internal SafeLsaLogonProcessHandle(IntPtr handle) : base(true) { SetHandle(handle); } internal static SafeLsaLogonProcessHandle InvalidHandle { get { return new SafeLsaLogonProcessHandle(IntPtr.Zero); } } override protected bool ReleaseHandle() { // LsaDeregisterLogonProcess returns an NTSTATUS return NativeMethods.LsaDeregisterLogonProcess(handle) >= 0; } } internal sealed class SafeLsaReturnBufferHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeLsaReturnBufferHandle() : base(true) { } // 0 is an Invalid Handle internal SafeLsaReturnBufferHandle(IntPtr handle) : base(true) { SetHandle(handle); } internal static SafeLsaReturnBufferHandle InvalidHandle { get { return new SafeLsaReturnBufferHandle(IntPtr.Zero); } } override protected bool ReleaseHandle() { // LsaFreeReturnBuffer returns an NTSTATUS return NativeMethods.LsaFreeReturnBuffer(handle) >= 0; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- CompositeDataBoundControl.cs
- CompilerWrapper.cs
- XsdBuilder.cs
- LogSwitch.cs
- UnsafeNativeMethods.cs
- UnsafeNativeMethodsPenimc.cs
- ToggleProviderWrapper.cs
- DirectoryObjectSecurity.cs
- DataViewSetting.cs
- RelativeSource.cs
- StringBlob.cs
- ConfigurationSectionGroup.cs
- WebRequestModuleElement.cs
- StorageInfo.cs
- TimeStampChecker.cs
- FormClosingEvent.cs
- WindowsGrip.cs
- PageCatalogPart.cs
- VisualCollection.cs
- WebPartUserCapability.cs
- ColumnReorderedEventArgs.cs
- ZipIOExtraFieldElement.cs
- path.cs
- WhitespaceReader.cs
- XmlEntityReference.cs
- WebBrowser.cs
- XPathMessageFilterElement.cs
- GlyphElement.cs
- Part.cs
- HtmlContainerControl.cs
- _emptywebproxy.cs
- _emptywebproxy.cs
- RowVisual.cs
- DesignerGeometryHelper.cs
- SEHException.cs
- PlacementWorkspace.cs
- AffineTransform3D.cs
- DecryptedHeader.cs
- SQLInt32.cs
- FormViewPagerRow.cs
- ToolStripManager.cs
- TransformPatternIdentifiers.cs
- VectorCollectionValueSerializer.cs
- LinqDataView.cs
- InputScopeConverter.cs
- SchemaNotation.cs
- CharacterBuffer.cs
- EntityTemplateUserControl.cs
- WebPartConnectVerb.cs
- RSAPKCS1KeyExchangeDeformatter.cs
- QueryCursorEventArgs.cs
- PersonalizationStateInfoCollection.cs
- PointLightBase.cs
- ReadOnlyAttribute.cs
- XmlnsDefinitionAttribute.cs
- PageThemeParser.cs
- StylusCaptureWithinProperty.cs
- HttpCapabilitiesEvaluator.cs
- QualificationDataItem.cs
- UnknownWrapper.cs
- MTConfigUtil.cs
- HttpAsyncResult.cs
- PolyQuadraticBezierSegment.cs
- DataMisalignedException.cs
- DbConnectionInternal.cs
- ArgumentDirectionHelper.cs
- NameObjectCollectionBase.cs
- MarkupObject.cs
- WinInetCache.cs
- odbcmetadatacollectionnames.cs
- DataSvcMapFile.cs
- EllipseGeometry.cs
- TimelineCollection.cs
- VirtualPathUtility.cs
- TextRenderer.cs
- TypeToArgumentTypeConverter.cs
- ConstraintStruct.cs
- SizeConverter.cs
- DataGridViewRowEventArgs.cs
- DatePickerAutomationPeer.cs
- _ConnectStream.cs
- CodeMemberMethod.cs
- ContentPosition.cs
- FlowDocumentPaginator.cs
- IdentityNotMappedException.cs
- ToolboxComponentsCreatedEventArgs.cs
- RoleService.cs
- securitymgrsite.cs
- FormatterConverter.cs
- AddInController.cs
- HandlerBase.cs
- ReferencedCollectionType.cs
- SqlClientWrapperSmiStreamChars.cs
- ResourcePermissionBase.cs
- ErrorProvider.cs
- GridViewSortEventArgs.cs
- ProxyRpc.cs
- LinqDataView.cs
- ScriptControl.cs
- _NegoState.cs