Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / _SafeNetHandles.cs / 1305376 / _SafeNetHandles.cs
/*++ Copyright (c) Microsoft Corporation Module Name: _SafeNetHandles.cs Abstract: The file contains _all_ SafeHandles implementations for System.Net namespace. 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 Author: Alexei Vopilov 04-Sept-2002 Revision History: --*/ namespace System.Net { using System.Net.Cache; using System.Net.Sockets; using System.Net.NetworkInformation; using System.Security; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Threading; using System.Security.Authentication.ExtendedProtection; using System.Security.Permissions; using System.ComponentModel; using System.Text; using System.Globalization; using Microsoft.Win32.SafeHandles; using System.Runtime.ConstrainedExecution; using System.Diagnostics.CodeAnalysis; #if DEBUG // // This is a helper class for debugging GC-ed handles that we define. // As a general rule normal code path should always destroy handles explicitly // internal abstract class DebugSafeHandle: SafeHandleZeroOrMinusOneIsInvalid { string m_Trace; protected DebugSafeHandle(bool ownsHandle): base(ownsHandle) { Trace(); } protected DebugSafeHandle(IntPtr invalidValue, bool ownsHandle): base(ownsHandle) { SetHandle(invalidValue); Trace(); } [EnvironmentPermission(SecurityAction.Assert, Unrestricted=true)] private void Trace() { m_Trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n"; #if TRAVE (new FileIOPermission(PermissionState.Unrestricted)).Assert(); string stacktrace = Environment.StackTrace; m_Trace += stacktrace; FileIOPermission.RevertAssert(); #endif //TRAVE } [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] ~DebugSafeHandle() { GlobalLog.SetThreadSource(ThreadKinds.Finalization); GlobalLog.Print(m_Trace); } } // // This is a helper class for debugging GC-ed handles that we define. // As a general rule normal code path should always destroy handles explicitly // internal abstract class DebugCriticalHandleMinusOneIsInvalid : CriticalHandleMinusOneIsInvalid { string m_Trace; protected DebugCriticalHandleMinusOneIsInvalid(): base() { Trace(); } [EnvironmentPermission(SecurityAction.Assert, Unrestricted=true)] private void Trace() { m_Trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n"; GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName); #if TRAVE (new FileIOPermission(PermissionState.Unrestricted)).Assert(); string stacktrace = Environment.StackTrace; m_Trace += stacktrace; FileIOPermission.RevertAssert(); #endif //TRAVE } ~DebugCriticalHandleMinusOneIsInvalid() { GlobalLog.SetThreadSource(ThreadKinds.Finalization); GlobalLog.Print(m_Trace); } } // // This is a helper class for debugging GC-ed handles that we define. // As a general rule normal code path should always destroy handles explicitly // internal abstract class DebugSafeHandleMinusOneIsInvalid : SafeHandleMinusOneIsInvalid { string m_Trace; protected DebugSafeHandleMinusOneIsInvalid(bool ownsHandle): base(ownsHandle) { Trace(); } [EnvironmentPermission(SecurityAction.Assert, Unrestricted=true)] private void Trace() { m_Trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n"; GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName); #if TRAVE (new FileIOPermission(PermissionState.Unrestricted)).Assert(); string stacktrace = Environment.StackTrace; m_Trace += stacktrace; FileIOPermission.RevertAssert(); #endif //TRAVE } ~DebugSafeHandleMinusOneIsInvalid() { GlobalLog.SetThreadSource(ThreadKinds.Finalization); GlobalLog.Print(m_Trace); } } // // This is a helper class for debugging GC-ed handles that we define. // As a general rule normal code path should always destroy handles explicitly // internal abstract class DebugCriticalHandleZeroOrMinusOneIsInvalid : CriticalHandleZeroOrMinusOneIsInvalid { string m_Trace; protected DebugCriticalHandleZeroOrMinusOneIsInvalid(): base() { Trace(); } [SuppressMessage("Microsoft.Security","CA2106:SecureAsserts", Justification="DEBUG use only: Require access to Environment.StackTrace regardless of app permissions")] [EnvironmentPermission(SecurityAction.Assert, Unrestricted=true)] private void Trace() { m_Trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n"; GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName); #if TRAVE (new FileIOPermission(PermissionState.Unrestricted)).Assert(); string stacktrace = Environment.StackTrace; m_Trace += stacktrace; FileIOPermission.RevertAssert(); #endif //TRAVE } ~DebugCriticalHandleZeroOrMinusOneIsInvalid() { GlobalLog.SetThreadSource(ThreadKinds.Finalization); GlobalLog.Print(m_Trace); } } #endif // DEBUG #if !FEATURE_PAL /////////////////////////////////////////////////////////////// // // This is safe handle implementaion that depends on // ws2_32.dll freeaddrinfo. It's only used by Dns class // /////////////////////////////////////////////////////////////// [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class SafeFreeAddrInfo : DebugSafeHandle { #else internal sealed class SafeFreeAddrInfo : SafeHandleZeroOrMinusOneIsInvalid { #endif private const string WS2_32 = "ws2_32.dll"; private SafeFreeAddrInfo(): base(true) {} internal static int GetAddrInfo(string nodename, string servicename, ref AddressInfo hints, out SafeFreeAddrInfo outAddrInfo) { return UnsafeNclNativeMethods.SafeNetHandlesXPOrLater.getaddrinfo(nodename, servicename, ref hints, out outAddrInfo); } override protected bool ReleaseHandle() { UnsafeNclNativeMethods.SafeNetHandlesXPOrLater.freeaddrinfo(handle); return true; } } #endif // !FEATURE_PAL /////////////////////////////////////////////////////////////// // // This is safe handle factory for any object that depends on // KERNEL32 CloseHandle as the handle disposal method. // /////////////////////////////////////////////////////////////// [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class SafeCloseHandle : DebugCriticalHandleZeroOrMinusOneIsInvalid { #else internal sealed class SafeCloseHandle : CriticalHandleZeroOrMinusOneIsInvalid { #endif private const string SECURITY = "security.dll"; private const string ADVAPI32 = "advapi32.dll"; private const string HTTPAPI = "httpapi.dll"; private int _disposed; private SafeCloseHandle() : base() { } internal IntPtr DangerousGetHandle() { return handle; } protected override bool ReleaseHandle() { if (!IsInvalid) { if (Interlocked.Increment(ref _disposed) == 1) { return UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(handle); } } return true; } #if !FEATURE_PAL // This method will bypass refCount check done by VM // Means it will force handle release if has a valid value [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal void Abort() { ReleaseHandle(); SetHandleAsInvalid(); } #endif // !FEATURE_PAL } // // This class is a wrapper for Http.sys V2 request queue handle. // [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Suppress due to tools issues with unit test infrastructure")] [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class HttpRequestQueueV2Handle : DebugCriticalHandleZeroOrMinusOneIsInvalid { #else internal sealed class HttpRequestQueueV2Handle : CriticalHandleZeroOrMinusOneIsInvalid { #endif private int disposed; private HttpRequestQueueV2Handle() : base() { } internal IntPtr DangerousGetHandle() { return handle; } protected override bool ReleaseHandle() { if (!IsInvalid) { if (Interlocked.Increment(ref disposed) == 1) { return (UnsafeNclNativeMethods.SafeNetHandles.HttpCloseRequestQueue(handle) == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); } } return true; } } // // This class is a wrapper for Http.sys V2 server session. CreateServerSession returns an ID and not a real handle // but we use CriticalHandle because it provides us the guarantee that CloseServerSession will always get called. // [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class HttpServerSessionHandle : DebugCriticalHandleZeroOrMinusOneIsInvalid { #else internal sealed class HttpServerSessionHandle : CriticalHandleZeroOrMinusOneIsInvalid { #endif private int disposed; private ulong serverSessionId; internal HttpServerSessionHandle(ulong id) : base() { serverSessionId = id; // // This class uses no real handle so we need to set a dummy handle. Otherwise, IsInvalid always remains // true. // SetHandle(new IntPtr(1)); } internal ulong DangerousGetServerSessionId() { return serverSessionId; } protected override bool ReleaseHandle() { if (!IsInvalid) { if (Interlocked.Increment(ref disposed) == 1) { // // Closing server session also closes all open url groups under that server session. // return (UnsafeNclNativeMethods.HttpApi.HttpCloseServerSession(serverSessionId) == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); } } return true; } } // // SafeHandle to wrap handles created by IcmpCreateFile or Icmp6CreateFile // from either icmp.dll or iphlpapi.dll. These handles must be closed by // IcmpCloseHandle. // // Code creating handles will use ComNetOS.IsPostWin2K to determine // which DLL being used. This code uses same construct to determine // which DLL being used but stashes the OS query results away at ctor // time so it is always available at critical finalizer time. // [SuppressUnmanagedCodeSecurity] internal sealed class SafeCloseIcmpHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeCloseIcmpHandle() : base(true) { } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] override protected bool ReleaseHandle() { return UnsafeNetInfoNativeMethods.IcmpCloseHandle(handle); } } // // Used when working with WinHTTP APIs, like WinHttpOpen(). Holds the HINTERNET handle. // [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class SafeInternetHandle : DebugSafeHandle { #else internal sealed class SafeInternetHandle : SafeHandleZeroOrMinusOneIsInvalid { #endif public SafeInternetHandle() : base(true) { } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] protected override bool ReleaseHandle() { return UnsafeNclNativeMethods.WinHttp.WinHttpCloseHandle(handle); } } #if !FEATURE_PAL /////////////////////////////////////////////////////////////// // // A set of Safe Handles that depend on native FreeContextBuffer finalizer // /////////////////////////////////////////////////////////////// //-------------------------------------------------------- internal enum SecurDll { SECURITY = 0, SECUR32 = 1, SCHANNEL = 2, } //======================================================= [SuppressUnmanagedCodeSecurity] #if DEBUG internal abstract class SafeFreeContextBuffer : DebugSafeHandle { #else internal abstract class SafeFreeContextBuffer : SafeHandleZeroOrMinusOneIsInvalid { #endif protected SafeFreeContextBuffer(): base(true) {} // This must be ONLY called from this file and in the context of a CER [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal unsafe void Set(IntPtr value) { this.handle = value; } // // internal static int EnumeratePackages(SecurDll Dll, out int pkgnum, out SafeFreeContextBuffer pkgArray) { int res = -1; switch (Dll) { case SecurDll.SECURITY: SafeFreeContextBuffer_SECURITY pkgArray_SECURITY = null; res = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.EnumerateSecurityPackagesW(out pkgnum, out pkgArray_SECURITY); pkgArray = pkgArray_SECURITY; break; case SecurDll.SECUR32: SafeFreeContextBuffer_SECUR32 pkgArray_SECUR32 = null; res = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.EnumerateSecurityPackagesA(out pkgnum, out pkgArray_SECUR32); pkgArray = pkgArray_SECUR32; break; case SecurDll.SCHANNEL: SafeFreeContextBuffer_SCHANNEL pkgArray_SCHANNEL = null; res = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.EnumerateSecurityPackagesA(out pkgnum, out pkgArray_SCHANNEL); pkgArray = pkgArray_SCHANNEL; break; default: throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "Dll"); } if (res != 0 && pkgArray != null) { pkgArray.SetHandleAsInvalid(); } return res; } // // internal static SafeFreeContextBuffer CreateEmptyHandle(SecurDll dll) { switch (dll) { case SecurDll.SECURITY: return new SafeFreeContextBuffer_SECURITY(); case SecurDll.SECUR32: return new SafeFreeContextBuffer_SECUR32(); case SecurDll.SCHANNEL: return new SafeFreeContextBuffer_SCHANNEL(); default: throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "dll"); } } // // 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 switches between three non-interruptible helper methods. (This method can't be both non-interruptible and // reference imports from all three DLLs - doing so would cause all three DLLs to try to be bound to.) // public unsafe static int QueryContextAttributes(SecurDll dll, SafeDeleteContext phContext, ContextAttribute contextAttribute, byte* buffer, SafeHandle refHandle) { switch (dll) { case SecurDll.SECURITY: return QueryContextAttributes_SECURITY(phContext, contextAttribute, buffer, refHandle); case SecurDll.SECUR32: return QueryContextAttributes_SECUR32(phContext, contextAttribute, buffer, refHandle); case SecurDll.SCHANNEL: return QueryContextAttributes_SCHANNEL(phContext, contextAttribute, buffer, refHandle); default: return -1; } } private unsafe static int QueryContextAttributes_SECURITY( 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) { status = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); phContext.DangerousRelease(); } if (status == 0 && refHandle != null) { if (refHandle is SafeFreeContextBuffer) { ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); } else { ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); } } if (status != 0 && refHandle != null) { refHandle.SetHandleAsInvalid(); } } return status; } private unsafe static int QueryContextAttributes_SECUR32( 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) { status = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.QueryContextAttributesA(ref phContext._handle, contextAttribute, buffer); phContext.DangerousRelease(); } if (status == 0 && refHandle != null) { if (refHandle is SafeFreeContextBuffer) { ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); } else { ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); } } if (status != 0 && refHandle != null) { refHandle.SetHandleAsInvalid(); } } return status; } private unsafe static int QueryContextAttributes_SCHANNEL( 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) { status = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.QueryContextAttributesA(ref phContext._handle, contextAttribute, buffer); phContext.DangerousRelease(); } if (status == 0 && refHandle != null) { if (refHandle is SafeFreeContextBuffer) { ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); } else { ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); } } if (status != 0 && refHandle != null) { refHandle.SetHandleAsInvalid(); } } return status; } } //======================================================= [SuppressUnmanagedCodeSecurity] internal sealed class SafeFreeContextBuffer_SECURITY : SafeFreeContextBuffer { private const string SECURITY = "security.dll"; internal SafeFreeContextBuffer_SECURITY(): base() {} override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles_SECURITY.FreeContextBuffer(handle) == 0; } } //======================================================= [SuppressUnmanagedCodeSecurity] internal sealed class SafeFreeContextBuffer_SCHANNEL : SafeFreeContextBuffer { private const string SCHANNEL = "schannel.dll"; internal SafeFreeContextBuffer_SCHANNEL(): base() {} override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.FreeContextBuffer(handle) == 0; } } //======================================================== [SuppressUnmanagedCodeSecurity] internal sealed class SafeFreeContextBuffer_SECUR32: SafeFreeContextBuffer { private const string SECUR32 = "secur32.dll"; internal SafeFreeContextBuffer_SECUR32(): base() {} override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles_SECUR32.FreeContextBuffer(handle) == 0; } } #endif // !FEATURE_PAL /////////////////////////////////////////////////////////////// // // This is implementaion of Safe AllocHGlobal which is turned out // to be LocalAlloc down in CLR // /////////////////////////////////////////////////////////////// [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class SafeLocalFree : DebugSafeHandle { #else internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid { #endif private const int LMEM_FIXED = 0; private const int NULL = 0; // This returned handle cannot be modified by the application. public static SafeLocalFree Zero = new SafeLocalFree(false); private SafeLocalFree() : base(true) {} private SafeLocalFree(bool ownsHandle) : base(ownsHandle) {} public static SafeLocalFree LocalAlloc(int cb) { SafeLocalFree result = UnsafeNclNativeMethods.SafeNetHandles.LocalAlloc(LMEM_FIXED, (UIntPtr) cb); if (result.IsInvalid) { result.SetHandleAsInvalid(); throw new OutOfMemoryException(); } return result; } override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; } } /////////////////////////////////////////////////////////////// // // A few Win32 APIs return pointers to blobs that need GlobalFree(). // /////////////////////////////////////////////////////////////// [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class SafeGlobalFree : DebugSafeHandle { #else internal sealed class SafeGlobalFree : SafeHandleZeroOrMinusOneIsInvalid { #endif private SafeGlobalFree() : base(true) { } private SafeGlobalFree(bool ownsHandle) : base(ownsHandle) { } override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles.GlobalFree(handle) == IntPtr.Zero; } } [ComVisible(false)] #if DEBUG internal sealed class SafeOverlappedFree : DebugSafeHandle { #else internal sealed class SafeOverlappedFree : SafeHandleZeroOrMinusOneIsInvalid { #endif private const int LPTR = 0x0040; private SafeCloseSocket _socketHandle; private SafeOverlappedFree() : base(true) {} private SafeOverlappedFree(bool ownsHandle) : base(ownsHandle) {} public static SafeOverlappedFree Alloc() { SafeOverlappedFree result = UnsafeNclNativeMethods.SafeNetHandlesSafeOverlappedFree.LocalAlloc(LPTR, (UIntPtr) Win32.OverlappedSize); if (result.IsInvalid) { result.SetHandleAsInvalid(); throw new OutOfMemoryException(); } return result; } public static SafeOverlappedFree Alloc(SafeCloseSocket socketHandle) { SafeOverlappedFree result = Alloc(); result._socketHandle = socketHandle; return result; } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public void Close (bool resetOwner) { RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { if (resetOwner) { _socketHandle = null; } Close(); } } unsafe override protected bool ReleaseHandle() { SafeCloseSocket socketHandle = _socketHandle; if (socketHandle != null && !socketHandle.IsInvalid) { // We are being finalized while the I/O operation associated // with the current overlapped is still pending (e.g. on app // domain shutdown). The socket has to be closed first to // avoid reuse after delete of the native overlapped structure. socketHandle.Dispose(); } // Release the native overlapped structure return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; } } #if !FEATURE_PAL [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class SafeLoadLibrary : DebugSafeHandle { #else internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid { #endif private const string KERNEL32 = "kernel32.dll"; public static readonly SafeLoadLibrary Zero = new SafeLoadLibrary(false); private SafeLoadLibrary() : base(true) { } private SafeLoadLibrary(bool ownsHandle) : base(ownsHandle) { } public unsafe static SafeLoadLibrary LoadLibraryEx(string library) { SafeLoadLibrary result = ComNetOS.IsWin9x ? UnsafeNclNativeMethods.SafeNetHandles.LoadLibraryExA(library, null, 0): UnsafeNclNativeMethods.SafeNetHandles.LoadLibraryExW(library, null, 0); if (result.IsInvalid) { result.SetHandleAsInvalid(); } return result; } protected override bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles.FreeLibrary(handle); } } /////////////////////////////////////////////////////////////// // // Implementation of handles that require CertFreeCertificateChain // /////////////////////////////////////////////////////////////// [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class SafeFreeCertChain : DebugSafeHandle { #else internal sealed class SafeFreeCertChain : SafeHandleZeroOrMinusOneIsInvalid { #endif private const string CRYPT32 = "crypt32.dll"; // This ctor will create a handle that we >>don't<< own internal SafeFreeCertChain(IntPtr handle) : base(false) { SetHandle(handle); } public override string ToString() { return "0x"+DangerousGetHandle().ToString("x"); } override protected bool ReleaseHandle() { UnsafeNclNativeMethods.SafeNetHandles.CertFreeCertificateChain(handle); return true; } } /////////////////////////////////////////////////////////////// // // Implementation of handles required CertFreeCertificateContext // /////////////////////////////////////////////////////////////// [SuppressUnmanagedCodeSecurity] #if DEBUG internal sealed class SafeFreeCertContext : DebugSafeHandle { #else internal sealed class SafeFreeCertContext : SafeHandleZeroOrMinusOneIsInvalid { #endif private const string CRYPT32 = "crypt32.dll"; private const string ADVAPI32 = "advapi32.dll"; internal SafeFreeCertContext() : base(true) {} // This must be ONLY called from this file within a CER. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal unsafe void Set(IntPtr value) { this.handle = value; } const uint CRYPT_ACQUIRE_SILENT_FLAG = 0x00000040; override protected bool ReleaseHandle() { UnsafeNclNativeMethods.SafeNetHandles.CertFreeCertificateContext(handle); return true; } } [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 override string ToString() { { return HandleHi.ToString("x") + ":" + HandleLo.ToString("x");} } } /////////////////////////////////////////////////////////////// // // Implementation of handles dependable on FreeCredentialsHandle // // /////////////////////////////////////////////////////////////// //----------------------------------------------------------- #if DEBUG internal abstract class SafeFreeCredentials : DebugSafeHandle { #else internal abstract class SafeFreeCredentials : SafeHandle { #endif internal SSPIHandle _handle; //should be always used as by ref in PINvokes parameters protected SafeFreeCredentials(): base(IntPtr.Zero, true) { _handle = new SSPIHandle(); } #if TRAVE public override string ToString() { return "0x"+_handle.ToString(); } #endif public override bool IsInvalid { get {return IsClosed || _handle.IsZero;} } #if DEBUG //This method should never be called for this type public new IntPtr DangerousGetHandle() { throw new InvalidOperationException(); } #endif public unsafe static int AcquireCredentialsHandle( SecurDll dll, string package, CredentialUse intent, ref AuthIdentity authdata, out SafeFreeCredentials outCredential ) { GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#1(" + dll + "," + package + ", " + intent + ", " + authdata + ")" ); int errorCode = -1; long timeStamp; switch (dll) { case SecurDll.SECURITY: outCredential = new SafeFreeCredential_SECURITY(); RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.AcquireCredentialsHandleW( null, package, (int)intent, null, ref authdata, null, null, ref outCredential._handle, out timeStamp ); } break; case SecurDll.SECUR32: outCredential = new SafeFreeCredential_SECUR32(); RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.AcquireCredentialsHandleA( null, package, (int)intent, null, ref authdata, null, null, ref outCredential._handle, out timeStamp ); } break; default: throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "Dll"); } #if TRAVE GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x" + String.Format("{0:x}", errorCode) + ", handle = " + outCredential.ToString() ); #endif if (errorCode != 0) { outCredential.SetHandleAsInvalid(); } return errorCode; } public unsafe static int AcquireDefaultCredential( SecurDll dll, string package, CredentialUse intent, out SafeFreeCredentials outCredential ) { GlobalLog.Print("SafeFreeCredentials::AcquireDefaultCredential(" + dll + "," + package + ", " + intent + ")" ); int errorCode = -1; long timeStamp; switch (dll) { case SecurDll.SECURITY: outCredential = new SafeFreeCredential_SECURITY(); RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.AcquireCredentialsHandleW( null, package, (int)intent, null, IntPtr.Zero, null, null, ref outCredential._handle, out timeStamp ); } break; case SecurDll.SECUR32: outCredential = new SafeFreeCredential_SECUR32(); RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.AcquireCredentialsHandleA( null, package, (int)intent, null, IntPtr.Zero, null, null, ref outCredential._handle, out timeStamp ); } break; default: throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "Dll"); } #if TRAVE GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x" + errorCode.ToString("x") + ", handle = " + outCredential.ToString() ); #endif if (errorCode != 0) { outCredential.SetHandleAsInvalid(); } return errorCode; } public unsafe static int AcquireCredentialsHandle( SecurDll dll, string package, CredentialUse intent, ref SecureCredential authdata, out SafeFreeCredentials outCredential ) { GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#2(" + dll + "," + package + ", " + intent + ", " + authdata + ")" ); int errorCode = -1; long timeStamp; // If there is a certificate, wrap it into an array. // Not threadsafe. IntPtr copiedPtr = authdata.certContextArray; try { IntPtr certArrayPtr = new IntPtr(&copiedPtr); if (copiedPtr != IntPtr.Zero) { authdata.certContextArray = certArrayPtr; } switch (dll) { case SecurDll.SECURITY: outCredential = new SafeFreeCredential_SECURITY(); RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.AcquireCredentialsHandleW( null, package, (int)intent, null, ref authdata, null, null, ref outCredential._handle, out timeStamp ); } break; case SecurDll.SCHANNEL: outCredential = new SafeFreeCredential_SCHANNEL(); RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.AcquireCredentialsHandleA( null, package, (int)intent, null, ref authdata, null, null, ref outCredential._handle, out timeStamp ); } break; default: throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "Dll"); } } finally { authdata.certContextArray = copiedPtr; } #if TRAVE GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x" + errorCode.ToString("x") + ", handle = " + outCredential.ToString() ); #endif if (errorCode != 0) { outCredential.SetHandleAsInvalid(); } return errorCode; } } // // This is a class holding a Credential handle reference, used for static handles cache // #if DEBUG internal sealed class SafeCredentialReference: DebugCriticalHandleMinusOneIsInvalid { #else internal sealed class SafeCredentialReference: CriticalHandleMinusOneIsInvalid { #endif // // Static cache will return the target handle if found the reference in the table. // internal SafeFreeCredentials _Target; // // internal static SafeCredentialReference CreateReference(SafeFreeCredentials target) { SafeCredentialReference result = new SafeCredentialReference(target); if (result.IsInvalid) return null; return result; } private SafeCredentialReference(SafeFreeCredentials target): base() { // Bumps up the refcount on Target to signify that target handle is statically cached so // its dispose should be postponed bool b = false; RuntimeHelpers.PrepareConstrainedRegions(); try { target.DangerousAddRef(ref b); } catch { if (b) { target.DangerousRelease(); b = false; } } finally { if (b) { _Target = target; SetHandle(new IntPtr(0)); // make this handle valid } } } override protected bool ReleaseHandle() { SafeFreeCredentials target = _Target; if (target != null) target.DangerousRelease(); _Target = null; return true; } } //====================================================================== [SuppressUnmanagedCodeSecurity] internal sealed class SafeFreeCredential_SECURITY: SafeFreeCredentials { private const string SECURITY = "security.Dll"; public SafeFreeCredential_SECURITY() : base() {} override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles_SECURITY.FreeCredentialsHandle(ref _handle) == 0; } } //====================================================================== [SuppressUnmanagedCodeSecurity] internal sealed class SafeFreeCredential_SECUR32: SafeFreeCredentials { private const string SECUR32 = "secur32.Dll"; public SafeFreeCredential_SECUR32() : base() {} override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles_SECUR32.FreeCredentialsHandle(ref _handle) == 0; } } //===================================================================== [SuppressUnmanagedCodeSecurity] internal sealed class SafeFreeCredential_SCHANNEL: SafeFreeCredentials { private const string SCHANNEL = "schannel.Dll"; public SafeFreeCredential_SCHANNEL() : base() {} override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.FreeCredentialsHandle(ref _handle) == 0; } } /////////////////////////////////////////////////////////////// // // Implementation of handles that are dependent on DeleteSecurityContext // // /////////////////////////////////////////////////////////////// #if DEBUG internal abstract class SafeDeleteContext : DebugSafeHandle { #else internal abstract class SafeDeleteContext : SafeHandle { #endif private const string dummyStr = " "; private static readonly byte[] dummyBytes = new byte[] {0}; // // ATN: _handle is internal since it is used on PInvokes by other wrapper methods. // However all such wrappers MUST manually and reliably adjust refCounter of SafeDeleteContext handle. // internal SSPIHandle _handle; protected SafeFreeCredentials _EffectiveCredential; protected SafeDeleteContext(): base(IntPtr.Zero, true) { _handle = new SSPIHandle(); } public override bool IsInvalid { get { return IsClosed || _handle.IsZero; } } public override string ToString() { return _handle.ToString(); } #if DEBUG //This method should never be called for this type public new IntPtr DangerousGetHandle() { throw new InvalidOperationException(); } #endif //-------------------------------------------------------------------- internal unsafe static int InitializeSecurityContext( SecurDll dll, ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, string targetName, ContextFlags inFlags, Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, ref ContextFlags outFlags) { #if TRAVE GlobalLog.Enter("SafeDeleteContext::InitializeSecurityContext"); GlobalLog.Print(" DLL = " + dll); GlobalLog.Print(" credential = " + inCredentials.ToString()); GlobalLog.Print(" refContext = " + ValidationHelper.ToString(refContext)); GlobalLog.Print(" targetName = " + targetName); GlobalLog.Print(" inFlags = " + inFlags); // GlobalLog.Print(" reservedI = 0x0"); // GlobalLog.Print(" endianness = " + endianness); if (inSecBuffers==null) { GlobalLog.Print(" inSecBuffers = (null)"); } else { GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); // for (int index=0; index0) { 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 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; } // // 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. // // 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_SECUR32( ref SafeFreeCredentials inCredentials, void* inContextPtr, byte* targetName, ContextFlags inFlags, Endianness endianness, SecurityBufferDescriptor inputBuffer, SafeDeleteContext outContext, SecurityBufferDescriptor outputBuffer, ref ContextFlags attributes, SafeFreeContextBuffer handleTemplate) { int errorCode = (int) SecurityStatus.InvalidHandle; 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 { SSPIHandle credentialHandle = inCredentials._handle; long timeStamp; if (b1 && b2) { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.InitializeSecurityContextA( 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; } // // 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. // // 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_SCHANNEL( ref SafeFreeCredentials inCredentials, void* inContextPtr, byte* targetName, ContextFlags inFlags, Endianness endianness, SecurityBufferDescriptor inputBuffer, SafeDeleteContext outContext, SecurityBufferDescriptor outputBuffer, ref ContextFlags attributes, SafeFreeContextBuffer handleTemplate) { int errorCode = (int) SecurityStatus.InvalidHandle; 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 { SSPIHandle credentialHandle = inCredentials._handle; long timeStamp; if (b1 && b2) { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.InitializeSecurityContextA( 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 unsafe static int AcceptSecurityContext( SecurDll dll, ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, ContextFlags inFlags, Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, ref ContextFlags outFlags) { #if TRAVE GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex"); GlobalLog.Print(" DLL = " + dll); GlobalLog.Print(" credential = " + inCredentials.ToString()); GlobalLog.Print(" refContext = " + ValidationHelper.ToString(refContext)); GlobalLog.Print(" inFlags = " + inFlags); // GlobalLog.Print(" endianness = " + endianness); // GlobalLog.Print(" inSecBuffer = " + SecurityBuffer.ToString(inSecBuffer)); // if (inSecBuffers==null) { GlobalLog.Print(" inSecBuffers = (null)"); } else { GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); // for (int index=0; index 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 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; } // // 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. // // 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 MustRunAcceptSecurityContext_SECUR32( ref SafeFreeCredentials inCredentials, void* inContextPtr, SecurityBufferDescriptor inputBuffer, ContextFlags inFlags, Endianness endianness, SafeDeleteContext outContext, SecurityBufferDescriptor outputBuffer, ref ContextFlags outFlags, SafeFreeContextBuffer handleTemplate) { int errorCode = (int) SecurityStatus.InvalidHandle; 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 { SSPIHandle credentialHandle = inCredentials._handle; long timeStamp; if (b1 && b2) { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.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; } // // 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. // // 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 MustRunAcceptSecurityContext_SCHANNEL( ref SafeFreeCredentials inCredentials, void* inContextPtr, SecurityBufferDescriptor inputBuffer, ContextFlags inFlags, Endianness endianness, SafeDeleteContext outContext, SecurityBufferDescriptor outputBuffer, ref ContextFlags outFlags, SafeFreeContextBuffer handleTemplate) { int errorCode = (int) SecurityStatus.InvalidHandle; 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 { SSPIHandle credentialHandle = inCredentials._handle; long timeStamp; if (b1 && b2) { errorCode = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.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; } // // // internal unsafe static int CompleteAuthToken( SecurDll dll, ref SafeDeleteContext refContext, SecurityBuffer[] inSecBuffers) { GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken"); GlobalLog.Print(" DLL = " + dll); GlobalLog.Print(" refContext = " + ValidationHelper.ToString(refContext)); #if TRAVE GlobalLog.Print(" inSecBuffers[] = length:" + inSecBuffers.Length); // for (int index=0; index (ref m_InnerSocket, null); if (innerSocket != null) { innerSocket.DangerousRelease(); } return true; } internal void CloseAsIs() { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { #if DEBUG // If this throws it could be very bad. try { #endif InnerSafeCloseSocket innerSocket = m_InnerSocket == null ? null : Interlocked.Exchange (ref m_InnerSocket, null); Close(); if (innerSocket != null) { // Wait until it's safe. while (!m_Released) { Thread.SpinWait(1); } // Now free it with blocking. innerSocket.BlockingRelease(); } #if DEBUG } catch (Exception exception) { if (!NclUtilities.IsFatal(exception)){ GlobalLog.Assert("SafeCloseSocket::CloseAsIs(handle:" + handle.ToString("x") + ")", exception.Message); } throw; } #endif } } internal class InnerSafeCloseSocket : SafeHandleMinusOneIsInvalid { protected InnerSafeCloseSocket() : base(true) { } private static readonly byte [] tempBuffer = new byte[1]; private bool m_Blockable; public override bool IsInvalid { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get { return IsClosed || base.IsInvalid; } } // This method is implicitly reliable and called from a CER. protected override bool ReleaseHandle() { bool ret = false; #if DEBUG try { #endif GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ")"); SocketError errorCode; // If m_Blockable was set in BlockingRelease, it's safe to block here, which means // we can honor the linger options set on the socket. It also means closesocket() might return WSAEWOULDBLOCK, in which // case we need to do some recovery. if (m_Blockable) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") Following 'blockable' branch."); errorCode = UnsafeNclNativeMethods.SafeNetHandles.closesocket(handle); #if DEBUG m_CloseSocketHandle = handle; m_CloseSocketResult = errorCode; #endif if (errorCode == SocketError.SocketError) errorCode = (SocketError) Marshal.GetLastWin32Error(); GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket()#1:" + errorCode.ToString()); // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed. if (errorCode != SocketError.WouldBlock) { return ret = errorCode == SocketError.Success; } // The socket must be non-blocking with a linger timeout set. // We have to set the socket to blocking. int nonBlockCmd = 0; errorCode = UnsafeNclNativeMethods.SafeNetHandles.ioctlsocket( handle, IoctlSocketConstants.FIONBIO, ref nonBlockCmd); if (errorCode == SocketError.SocketError) errorCode = (SocketError) Marshal.GetLastWin32Error(); GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket()#1:" + errorCode.ToString()); // This can fail if there's a pending WSAEventSelect. Try canceling it. if (errorCode == SocketError.InvalidArgument) { errorCode = UnsafeNclNativeMethods.SafeNetHandles.WSAEventSelect( handle, IntPtr.Zero, AsyncEventBits.FdNone); GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") WSAEventSelect():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString()); // Now retry the ioctl. errorCode = UnsafeNclNativeMethods.SafeNetHandles.ioctlsocket( handle, IoctlSocketConstants.FIONBIO, ref nonBlockCmd); GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket#2():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString()); } // If that succeeded, try again. if (errorCode == SocketError.Success) { errorCode = UnsafeNclNativeMethods.SafeNetHandles.closesocket(handle); #if DEBUG m_CloseSocketHandle = handle; m_CloseSocketResult = errorCode; #endif if (errorCode == SocketError.SocketError) errorCode = (SocketError) Marshal.GetLastWin32Error(); GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#2():" + errorCode.ToString()); // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed. if (errorCode != SocketError.WouldBlock) { return ret = errorCode == SocketError.Success; } } // It failed. Fall through to the regular abortive close. } // By default or if CloseAsIs() path failed, set linger timeout to zero to get an abortive close (RST). Linger lingerStruct; lingerStruct.OnOff = 1; lingerStruct.Time = 0; errorCode = UnsafeNclNativeMethods.SafeNetHandles.setsockopt( handle, SocketOptionLevel.Socket, SocketOptionName.Linger, ref lingerStruct, 4); #if DEBUG m_CloseSocketLinger = errorCode; #endif if (errorCode == SocketError.SocketError) errorCode = (SocketError) Marshal.GetLastWin32Error(); GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") setsockopt():" + errorCode.ToString()); if (errorCode != SocketError.Success && errorCode != SocketError.InvalidArgument && errorCode != SocketError.ProtocolOption) { // Too dangerous to try closesocket() - it might block! return ret = false; } errorCode = UnsafeNclNativeMethods.SafeNetHandles.closesocket(handle); #if DEBUG m_CloseSocketHandle = handle; m_CloseSocketResult = errorCode; #endif GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#3():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString()); return ret = errorCode == SocketError.Success; #if DEBUG } catch (Exception exception) { if (!NclUtilities.IsFatal(exception)){ GlobalLog.Assert("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ")", exception.Message); } ret = true; // Avoid a second assert. throw; } finally { m_CloseSocketThread = Thread.CurrentThread.ManagedThreadId; m_CloseSocketTick = Environment.TickCount; GlobalLog.Assert(ret, "SafeCloseSocket::ReleaseHandle(handle:{0:x})|ReleaseHandle failed.", handle); } #endif } #if DEBUG private IntPtr m_CloseSocketHandle; private SocketError m_CloseSocketResult = unchecked((SocketError) 0xdeadbeef); private SocketError m_CloseSocketLinger = unchecked((SocketError) 0xdeadbeef); private int m_CloseSocketThread; private int m_CloseSocketTick; #endif // Use this method to close the socket handle using the linger options specified on the socket. // Guaranteed to only be called once, under a CER, and not if regular DangerousRelease is called. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal void BlockingRelease() { m_Blockable = true; DangerousRelease(); } internal unsafe static InnerSafeCloseSocket CreateWSASocket(byte* pinnedBuffer) { //-1 is the value for FROM_PROTOCOL_INFO InnerSafeCloseSocket result = UnsafeNclNativeMethods.OSSOCK.WSASocket((AddressFamily) (-1),(SocketType) (-1),(ProtocolType) (-1), pinnedBuffer, 0, SocketConstructorFlags.WSA_FLAG_OVERLAPPED); if (result.IsInvalid) { result.SetHandleAsInvalid(); } return result; } internal static InnerSafeCloseSocket CreateWSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) { InnerSafeCloseSocket result = UnsafeNclNativeMethods.OSSOCK.WSASocket(addressFamily, socketType, protocolType, IntPtr.Zero, 0, SocketConstructorFlags.WSA_FLAG_OVERLAPPED); if (result.IsInvalid) { result.SetHandleAsInvalid(); } return result; } internal static InnerSafeCloseSocket Accept(SafeCloseSocket socketHandle, byte[] socketAddress, ref int socketAddressSize) { InnerSafeCloseSocket result = UnsafeNclNativeMethods.SafeNetHandles.accept(socketHandle.DangerousGetHandle(), socketAddress, ref socketAddressSize); if (result.IsInvalid) { result.SetHandleAsInvalid(); } return result; } } } [SuppressUnmanagedCodeSecurity] internal sealed class SafeCloseSocketAndEvent: SafeCloseSocket { internal SafeCloseSocketAndEvent() : base() {} private AutoResetEvent waitHandle; override protected bool ReleaseHandle() { bool result = base.ReleaseHandle(); DeleteEvent(); return result; } internal static SafeCloseSocketAndEvent CreateWSASocketWithEvent(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, bool autoReset, bool signaled){ SafeCloseSocketAndEvent result = new SafeCloseSocketAndEvent(); CreateSocket(InnerSafeCloseSocket.CreateWSASocket(addressFamily, socketType, protocolType), result); if (result.IsInvalid) { throw new SocketException(); } result.waitHandle = new AutoResetEvent(false); CompleteInitialization(result); return result; } internal static void CompleteInitialization(SafeCloseSocketAndEvent socketAndEventHandle){ SafeWaitHandle handle = socketAndEventHandle.waitHandle.SafeWaitHandle; bool b = false; RuntimeHelpers.PrepareConstrainedRegions(); try { handle.DangerousAddRef(ref b); } catch { if (b) { handle.DangerousRelease(); socketAndEventHandle.waitHandle = null; b = false; } } finally { if (b) { handle.Dispose(); } } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private void DeleteEvent(){ try{ if(waitHandle != null){ waitHandle.SafeWaitHandle.DangerousRelease(); } } catch{ } } internal WaitHandle GetEventHandle(){ return waitHandle; } } // Based on SafeLocalFree [SuppressUnmanagedCodeSecurity] internal class SafeLocalFreeChannelBinding : ChannelBinding { private const int LMEM_FIXED = 0; private int size; public override int Size { get { return size; } } public static SafeLocalFreeChannelBinding LocalAlloc(int cb) { SafeLocalFreeChannelBinding result; result = UnsafeNclNativeMethods.SafeNetHandles.LocalAllocChannelBinding(LMEM_FIXED, (UIntPtr)cb); if (result.IsInvalid) { result.SetHandleAsInvalid(); throw new OutOfMemoryException(); } result.size = cb; return result; } override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; } } // Based on SafeFreeContextBuffer [SuppressUnmanagedCodeSecurity] internal abstract class SafeFreeContextBufferChannelBinding : ChannelBinding { private int size; public override int Size { get { return size; } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal unsafe void Set(IntPtr value) { this.handle = value; } internal static SafeFreeContextBufferChannelBinding CreateEmptyHandle(SecurDll dll) { switch (dll) { case SecurDll.SECURITY: return new SafeFreeContextBufferChannelBinding_SECURITY(); case SecurDll.SECUR32: return new SafeFreeContextBufferChannelBinding_SECUR32(); case SecurDll.SCHANNEL: return new SafeFreeContextBufferChannelBinding_SCHANNEL(); default: throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "dll"); } } public unsafe static int QueryContextChannelBinding(SecurDll dll, SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding refHandle) { switch (dll) { case SecurDll.SECURITY: return QueryContextChannelBinding_SECURITY(phContext, contextAttribute, buffer, refHandle); case SecurDll.SECUR32: return QueryContextChannelBinding_SECUR32(phContext, contextAttribute, buffer, refHandle); case SecurDll.SCHANNEL: return QueryContextChannelBinding_SCHANNEL(phContext, contextAttribute, buffer, refHandle); default: return -1; } } private unsafe static int QueryContextChannelBinding_SECURITY(SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding 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) { status = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); phContext.DangerousRelease(); } if (status == 0 && refHandle != null) { refHandle.Set((*buffer).pBindings); refHandle.size = (*buffer).BindingsLength; } if (status != 0 && refHandle != null) { refHandle.SetHandleAsInvalid(); } } return status; } private unsafe static int QueryContextChannelBinding_SECUR32(SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding 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) { status = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.QueryContextAttributesA(ref phContext._handle, contextAttribute, buffer); phContext.DangerousRelease(); } if (status == 0 && refHandle != null) { refHandle.Set((*buffer).pBindings); refHandle.size = (*buffer).BindingsLength; } if (status != 0 && refHandle != null) { refHandle.SetHandleAsInvalid(); } } return status; } private unsafe static int QueryContextChannelBinding_SCHANNEL(SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding 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) { status = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.QueryContextAttributesA(ref phContext._handle, contextAttribute, buffer); phContext.DangerousRelease(); } if (status == 0 && refHandle != null) { refHandle.Set((*buffer).pBindings); refHandle.size = (*buffer).BindingsLength; } if (status != 0 && refHandle != null) { refHandle.SetHandleAsInvalid(); } } return status; } } [SuppressUnmanagedCodeSecurity] internal sealed class SafeFreeContextBufferChannelBinding_SECURITY : SafeFreeContextBufferChannelBinding { override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles_SECURITY.FreeContextBuffer(handle) == 0; } } [SuppressUnmanagedCodeSecurity] internal sealed class SafeFreeContextBufferChannelBinding_SCHANNEL : SafeFreeContextBufferChannelBinding { override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.FreeContextBuffer(handle) == 0; } } [SuppressUnmanagedCodeSecurity] internal sealed class SafeFreeContextBufferChannelBinding_SECUR32 : SafeFreeContextBufferChannelBinding { override protected bool ReleaseHandle() { return UnsafeNclNativeMethods.SafeNetHandles_SECUR32.FreeContextBuffer(handle) == 0; } } #if !FEATURE_PAL /////////////////////////////////////////////////////////////// // // This class implements a safe handle for WinInet cache stream // /////////////////////////////////////////////////////////////// #if DEBUG internal sealed class SafeUnlockUrlCacheEntryFile : DebugSafeHandle { #else internal sealed class SafeUnlockUrlCacheEntryFile : SafeHandleZeroOrMinusOneIsInvalid { #endif private string m_KeyString; private SafeUnlockUrlCacheEntryFile(string keyString): base(true) { m_KeyString = keyString; } #if DEBUG //This method should never be called for this type public new IntPtr DangerousGetHandle() { throw new InvalidOperationException(); } #endif override unsafe protected bool ReleaseHandle() { fixed (char *ptrStr = m_KeyString) { UnsafeNclNativeMethods.SafeNetHandles.UnlockUrlCacheEntryFileW(ptrStr, 0); } SetHandle(IntPtr.Zero); m_KeyString = null; return true; } internal unsafe static _WinInetCache.Status GetAndLockFile(string key, byte* entryPtr, ref int entryBufSize, out SafeUnlockUrlCacheEntryFile handle) { if (ValidationHelper.IsBlankString(key)) { throw new ArgumentNullException("key"); } handle = new SafeUnlockUrlCacheEntryFile(key); fixed (char* keyPtr = key) { return MustRunGetAndLockFile(keyPtr, entryPtr, ref entryBufSize, handle); } } // // Whis will check the result from PInvoke and make a valid safeHandle on success // unsafe private static _WinInetCache.Status MustRunGetAndLockFile(char* key, byte* entryPtr, ref int entryBufSize, SafeUnlockUrlCacheEntryFile handle) { _WinInetCache.Status error = _WinInetCache.Status.Success; // Run the body of this method as a non-interruptible block. RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { if (!UnsafeNclNativeMethods.SafeNetHandles.RetrieveUrlCacheEntryFileW(key, entryPtr, ref entryBufSize, 0)) { error = (_WinInetCache.Status)Marshal.GetLastWin32Error(); handle.SetHandleAsInvalid(); } else { // Hack: that will return 1 in place of a handle // The real handle here is a "key" string handle.SetHandle((IntPtr)1); } } return error; } } [System.Security.SuppressUnmanagedCodeSecurityAttribute()] internal sealed unsafe class SafeRegistryHandle : #if DEBUG DebugSafeHandle #else SafeHandleZeroOrMinusOneIsInvalid #endif { private SafeRegistryHandle() : base(true) { } internal static uint RegOpenKeyEx(IntPtr key, string subKey, uint ulOptions, uint samDesired, out SafeRegistryHandle resultSubKey) { return UnsafeNclNativeMethods.RegistryHelper.RegOpenKeyEx(key, subKey, ulOptions, samDesired, out resultSubKey); } internal uint RegOpenKeyEx(string subKey, uint ulOptions, uint samDesired, out SafeRegistryHandle resultSubKey) { return UnsafeNclNativeMethods.RegistryHelper.RegOpenKeyEx(this, subKey, ulOptions, samDesired, out resultSubKey); } internal uint RegCloseKey() { Close(); return resClose; } internal uint QueryValue(string name, out object data) { data = null; byte[] blob = null; uint size = 0; uint type; uint errorCode; while (true) { errorCode = UnsafeNclNativeMethods.RegistryHelper.RegQueryValueEx(this, name, IntPtr.Zero, out type, blob, ref size); if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA && (blob != null || errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)) { break; } blob = new byte[size]; } if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { return errorCode; } switch (type) { case UnsafeNclNativeMethods.RegistryHelper.REG_BINARY: if (size != blob.Length) { byte[] oldBlob = blob; blob = new byte[size]; Buffer.BlockCopy(oldBlob, 0, blob, 0, (int) size); } data = blob; return UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; default: return UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_SUPPORTED; } } internal uint RegNotifyChangeKeyValue(bool watchSubTree, uint notifyFilter, SafeWaitHandle regEvent, bool async) { return UnsafeNclNativeMethods.RegistryHelper.RegNotifyChangeKeyValue(this, watchSubTree, notifyFilter, regEvent, async); } internal static uint RegOpenCurrentUser(uint samDesired, out SafeRegistryHandle resultKey) { if (ComNetOS.IsWin9x) { return UnsafeNclNativeMethods.RegistryHelper.RegOpenKeyEx(UnsafeNclNativeMethods.RegistryHelper.HKEY_CURRENT_USER, null, 0, samDesired, out resultKey); } else { return UnsafeNclNativeMethods.RegistryHelper.RegOpenCurrentUser(samDesired, out resultKey); } } override protected bool ReleaseHandle() { if(!IsInvalid) resClose = UnsafeNclNativeMethods.RegistryHelper.RegCloseKey(handle); SetHandleAsInvalid(); return true; } private uint resClose; } #endif // !FEATURE_PAL } // 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
- ProvidersHelper.cs
- DataChangedEventManager.cs
- OleDbSchemaGuid.cs
- TypeSource.cs
- MetadataArtifactLoaderComposite.cs
- ZipIOModeEnforcingStream.cs
- WaitHandle.cs
- RowUpdatedEventArgs.cs
- BoolLiteral.cs
- Misc.cs
- BaseProcessor.cs
- PointConverter.cs
- EndOfStreamException.cs
- TrackingDataItem.cs
- XPathQilFactory.cs
- WaitHandleCannotBeOpenedException.cs
- ComNativeDescriptor.cs
- ShapingEngine.cs
- XmlNamespaceMappingCollection.cs
- NativeRightsManagementAPIsStructures.cs
- PhysicalOps.cs
- XPathDocumentIterator.cs
- ValidatorAttribute.cs
- DesignTimeVisibleAttribute.cs
- XmlComplianceUtil.cs
- FileEnumerator.cs
- ObjectTag.cs
- ResXResourceWriter.cs
- SerializationInfoEnumerator.cs
- NamespaceCollection.cs
- TraceUtils.cs
- MediaScriptCommandRoutedEventArgs.cs
- recordstate.cs
- XmlSchemaChoice.cs
- ClientBase.cs
- ErrorRuntimeConfig.cs
- Oid.cs
- WebControl.cs
- JsonWriter.cs
- ProcessThreadCollection.cs
- __Error.cs
- ModelMemberCollection.cs
- Material.cs
- XmlDataLoader.cs
- ServiceDurableInstance.cs
- SQLByteStorage.cs
- TransformConverter.cs
- DefaultEvaluationContext.cs
- PtsHost.cs
- LicenseManager.cs
- OdbcConnection.cs
- SmtpTransport.cs
- TransformGroup.cs
- ServiceModelEnumValidator.cs
- SqlClientPermission.cs
- AnimationClockResource.cs
- CallSiteHelpers.cs
- SubstitutionList.cs
- DefaultObjectMappingItemCollection.cs
- OrCondition.cs
- ComponentResourceKeyConverter.cs
- MappingModelBuildProvider.cs
- HttpRequestContext.cs
- HtmlPageAdapter.cs
- UriExt.cs
- TypeUtils.cs
- WebPartZoneBase.cs
- DbException.cs
- UpdatableGenericsFeature.cs
- DbQueryCommandTree.cs
- MappingSource.cs
- FunctionDescription.cs
- ResourceDescriptionAttribute.cs
- NamedPermissionSet.cs
- ErrorFormatterPage.cs
- StreamGeometry.cs
- XmlEntityReference.cs
- WindowsFont.cs
- Column.cs
- FilteredDataSetHelper.cs
- ScrollItemProviderWrapper.cs
- IPPacketInformation.cs
- SHA384Managed.cs
- PassportAuthenticationModule.cs
- ELinqQueryState.cs
- AdvancedBindingPropertyDescriptor.cs
- DragDeltaEventArgs.cs
- LineVisual.cs
- StylusPointPropertyInfoDefaults.cs
- Matrix3D.cs
- TextParaLineResult.cs
- CellTreeNode.cs
- CodeTypeDeclarationCollection.cs
- OdbcDataAdapter.cs
- WhitespaceRuleReader.cs
- RuntimeArgument.cs
- PerformanceCounters.cs
- GroupBox.cs
- TextBoxBase.cs
- KeyInfo.cs