25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

335 lines
12 KiB

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Diagnostics;
  10. using System.Diagnostics.CodeAnalysis;
  11. using System.Runtime.CompilerServices;
  12. using System.Runtime.ConstrainedExecution;
  13. using System.Runtime.InteropServices;
  14. using System.Security;
  15. using Microsoft.Win32.SafeHandles;
  16. namespace Security2
  17. {
  18. using HANDLE = System.IntPtr;
  19. internal sealed class SafeHGlobalHandle : IDisposable
  20. {
  21. #region Constructor and Destructor
  22. SafeHGlobalHandle()
  23. {
  24. pointer = IntPtr.Zero;
  25. }
  26. SafeHGlobalHandle(IntPtr handle)
  27. {
  28. pointer = handle;
  29. }
  30. ~SafeHGlobalHandle()
  31. {
  32. Dispose();
  33. }
  34. #endregion
  35. #region Public methods
  36. public static SafeHGlobalHandle InvalidHandle
  37. {
  38. get { return new SafeHGlobalHandle(IntPtr.Zero); }
  39. }
  40. /// <summary>
  41. /// Adds reference to other SafeHGlobalHandle objects, the pointer to
  42. /// which are refered to by this object. This is to ensure that such
  43. /// objects being referred to wouldn't be unreferenced until this object
  44. /// is active.
  45. ///
  46. /// For e.g. when this object is an array of pointers to other objects
  47. /// </summary>
  48. /// <param name="children">Collection of SafeHGlobalHandle objects
  49. /// referred to by this object.</param>
  50. public void AddSubReference(IEnumerable<SafeHGlobalHandle> children)
  51. {
  52. if (references == null)
  53. {
  54. references = new List<SafeHGlobalHandle>();
  55. }
  56. references.AddRange(children);
  57. }
  58. /// <summary>
  59. /// Allocates from unmanaged memory to represent an array of pointers
  60. /// and marshals the unmanaged pointers (IntPtr) to the native array
  61. /// equivalent.
  62. /// </summary>
  63. /// <param name="values">Array of unmanaged pointers</param>
  64. /// <returns>SafeHGlobalHandle object to an native (unmanaged) array of pointers</returns>
  65. public static SafeHGlobalHandle AllocHGlobal(IntPtr[] values)
  66. {
  67. SafeHGlobalHandle result = AllocHGlobal(IntPtr.Size * values.Length);
  68. Marshal.Copy(values, 0, result.pointer, values.Length);
  69. return result;
  70. }
  71. public static SafeHGlobalHandle AllocHGlobalStruct<T>(T obj) where T : struct
  72. {
  73. Debug.Assert(typeof(T).StructLayoutAttribute.Value == LayoutKind.Sequential);
  74. SafeHGlobalHandle result = AllocHGlobal(Marshal.SizeOf(typeof(T)));
  75. Marshal.StructureToPtr(obj, result.pointer, false);
  76. return result;
  77. }
  78. /// <summary>
  79. /// Allocates from unmanaged memory to represent an array of structures
  80. /// and marshals the structure elements to the native array of
  81. /// structures. ONLY structures with attribute StructLayout of
  82. /// LayoutKind.Sequential are supported.
  83. /// </summary>
  84. /// <typeparam name="T">Native structure type</typeparam>
  85. /// <param name="values">Collection of structure objects</param>
  86. /// <param name="count">Number of elements in the collection</param>
  87. /// <returns>SafeHGlobalHandle object to an native (unmanaged) array of structures</returns>
  88. public static SafeHGlobalHandle AllocHGlobal<T>(ICollection<T> values) where T : struct
  89. {
  90. Debug.Assert(typeof(T).StructLayoutAttribute.Value == LayoutKind.Sequential);
  91. return AllocHGlobal(0, values, values.Count);
  92. }
  93. /// <summary>
  94. /// Allocates from unmanaged memory to represent a structure with a
  95. /// variable length array at the end and marshal these structure
  96. /// elements. It is the callers responsibility to marshal what preceeds
  97. /// the trailinh array into the unmanaged memory. ONLY structures with
  98. /// attribute StructLayout of LayoutKind.Sequential are supported.
  99. /// </summary>
  100. /// <typeparam name="T">Type of the trailing array of structures</typeparam>
  101. /// <param name="prefixBytes">Number of bytes preceeding the trailing array of structures</param>
  102. /// <param name="values">Collection of structure objects</param>
  103. /// <param name="count"></param>
  104. /// <returns>SafeHGlobalHandle object to an native (unmanaged) structure
  105. /// with a trail array of structures</returns>
  106. public static SafeHGlobalHandle AllocHGlobal<T>(int prefixBytes, IEnumerable<T> values, int count) where T
  107. : struct
  108. {
  109. Debug.Assert(typeof(T).StructLayoutAttribute.Value == LayoutKind.Sequential);
  110. SafeHGlobalHandle result = AllocHGlobal(prefixBytes + Marshal.SizeOf(typeof(T)) * count);
  111. IntPtr ptr = new IntPtr(result.pointer.ToInt32() + prefixBytes);
  112. foreach (var value in values)
  113. {
  114. Marshal.StructureToPtr(value, ptr, false);
  115. ptr.Increment<T>();
  116. }
  117. return result;
  118. }
  119. /// <summary>
  120. /// Allocates from unmanaged memory to represent a unicode string (WSTR)
  121. /// and marshal this to a native PWSTR.
  122. /// </summary>
  123. /// <param name="s">String</param>
  124. /// <returns>SafeHGlobalHandle object to an native (unmanaged) unicode string</returns>
  125. public static SafeHGlobalHandle AllocHGlobal(string s)
  126. {
  127. return new SafeHGlobalHandle(Marshal.StringToHGlobalUni(s));
  128. }
  129. /// <summary>
  130. /// Operator to obtain the unmanaged pointer wrapped by the object. Note
  131. /// that the returned pointer is only valid for the lifetime of this
  132. /// object.
  133. /// </summary>
  134. /// <param name="safeHandle">SafeHGlobalHandle object</param>
  135. /// <returns>Unmanaged pointer wrapped by the object</returns>
  136. public IntPtr ToIntPtr()
  137. {
  138. return pointer;
  139. }
  140. #endregion
  141. #region IDisposable implmentation
  142. public void Dispose()
  143. {
  144. if (pointer != IntPtr.Zero)
  145. {
  146. Marshal.FreeHGlobal(pointer);
  147. pointer = IntPtr.Zero;
  148. }
  149. GC.SuppressFinalize(this);
  150. }
  151. #endregion
  152. #region Private implementation
  153. [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
  154. Justification = "Caller will dispose result")]
  155. static SafeHGlobalHandle AllocHGlobal(int cb)
  156. {
  157. if (cb < 0)
  158. {
  159. throw new ArgumentOutOfRangeException("cb", "The value of this argument must be non-negative");
  160. }
  161. SafeHGlobalHandle result = new SafeHGlobalHandle();
  162. //
  163. // CER
  164. //
  165. RuntimeHelpers.PrepareConstrainedRegions();
  166. try { }
  167. finally
  168. {
  169. result.pointer = Marshal.AllocHGlobal(cb);
  170. }
  171. return result;
  172. }
  173. #endregion
  174. #region Private members
  175. /// <summary>
  176. /// Maintainsreference to other SafeHGlobalHandle objects, the pointer
  177. /// to which are refered to by this object. This is to ensure that such
  178. /// objects being referred to wouldn't be unreferenced until this object
  179. /// is active.
  180. /// </summary>
  181. List<SafeHGlobalHandle> references;
  182. //
  183. // Using SafeHandle here doesn't buy much since the pointer is
  184. // eventually stashed into a native structure. Using a SafeHandle would
  185. // involve calling DangerousGetHandle in place of ToIntPtr which makes
  186. // code analysis report CA2001: Avoid calling problematic methods.
  187. //
  188. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
  189. /// <summary>
  190. /// Unmanaged pointer wrapped by this object
  191. /// </summary>
  192. IntPtr pointer;
  193. #endregion
  194. }
  195. //
  196. // Adopted from: http://msdn.microsoft.com/en-us/magazine/cc163823.aspx
  197. //
  198. /// <summary>
  199. /// Safe wrapper for HANDLE to a token.
  200. /// </summary>
  201. internal class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
  202. {
  203. #region Constructors
  204. /// <summary>
  205. /// This safehandle instance "owns" the handle, hence base(true)
  206. /// is being called. When safehandle is no longer in use it will
  207. /// call this class's ReleaseHandle method which will release
  208. /// the resources
  209. /// </summary>
  210. private SafeTokenHandle() : base(true) { }
  211. // 0 is an Invalid Handle
  212. internal SafeTokenHandle(HANDLE handle)
  213. : base(true)
  214. {
  215. SetHandle(handle);
  216. }
  217. #endregion
  218. internal static SafeTokenHandle InvalidHandle
  219. {
  220. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Retain to illustrate semantics")]
  221. get { return new SafeTokenHandle(HANDLE.Zero); }
  222. }
  223. #region Private implementation
  224. /// <summary>
  225. /// Release the HANDLE held by this instance
  226. /// </summary>
  227. /// <returns>true if the release was successful. false otherwise.</returns>
  228. override protected bool ReleaseHandle()
  229. {
  230. return NativeMethods.CloseHandle(handle);
  231. }
  232. #endregion
  233. #region Nested class for P/Invokes
  234. static class NativeMethods
  235. {
  236. [DllImport(Win32.KERNEL32_DLL, SetLastError = true),
  237. SuppressUnmanagedCodeSecurity,
  238. ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  239. [return: MarshalAs(UnmanagedType.Bool)]
  240. public static extern bool CloseHandle(HANDLE handle);
  241. }
  242. #endregion
  243. }
  244. /// <summary>
  245. /// Safe wrapper for AUTHZ_RESOURCE_MANAGER_HANDLE.
  246. /// </summary>
  247. internal class SafeAuthzRMHandle : SafeHandleZeroOrMinusOneIsInvalid
  248. {
  249. #region Constructors
  250. /// <summary>
  251. /// This safehandle instance "owns" the handle, hence base(true)
  252. /// is being called. When safehandle is no longer in use it will
  253. /// call this class's ReleaseHandle method which will release
  254. /// the resources
  255. /// </summary>
  256. SafeAuthzRMHandle() : base(true) { }
  257. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
  258. Justification = "Retain to illustrate semantics and for reuse")]
  259. SafeAuthzRMHandle(HANDLE handle)
  260. : base(true)
  261. {
  262. SetHandle(handle);
  263. }
  264. #endregion
  265. public static SafeAuthzRMHandle InvalidHandle
  266. {
  267. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
  268. Justification = "Retain to illustrate semantics")]
  269. get { return new SafeAuthzRMHandle(HANDLE.Zero); }
  270. }
  271. #region Private implementation
  272. /// <summary>
  273. /// Release the resource manager handle held by this instance
  274. /// </summary>
  275. /// <returns>true if the release was successful. false otherwise.</returns>
  276. override protected bool ReleaseHandle()
  277. {
  278. return NativeMethods.AuthzFreeResourceManager(handle);
  279. }
  280. #endregion
  281. #region Nested class for P/Invokes
  282. static class NativeMethods
  283. {
  284. [DllImport(Win32.AUTHZ_DLL, SetLastError = true),
  285. SuppressUnmanagedCodeSecurity,
  286. ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  287. [return: MarshalAs(UnmanagedType.Bool)]
  288. public static extern bool AuthzFreeResourceManager(HANDLE handle);
  289. }
  290. #endregion
  291. }
  292. }