CommonAcl.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. //
  2. // System.Security.AccessControl.CommonAcl implementation
  3. //
  4. // Authors:
  5. // Dick Porter <[email protected]>
  6. // Atsushi Enomoto <[email protected]>
  7. // James Bellinger <[email protected]>
  8. //
  9. // Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
  10. // Copyright (C) 2012 James Bellinger
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System.Collections.Generic;
  32. using System.Security.Principal;
  33. namespace System.Security.AccessControl
  34. {
  35. /* NB: Note the Remarks section in the CommonAcl class docs
  36. * concerning ACE management
  37. */
  38. public abstract class CommonAcl : GenericAcl
  39. {
  40. const int default_capacity = 10; // FIXME: not verified
  41. delegate bool RemoveAcesCallback (GenericAce ace);
  42. internal CommonAcl (bool isContainer, bool isDS, RawAcl rawAcl)
  43. {
  44. if (rawAcl == null) {
  45. rawAcl = new RawAcl (isDS ? AclRevisionDS : AclRevision, default_capacity);
  46. } else {
  47. // The RawAcl ACEs are cloned.
  48. byte[] binaryForm = new byte [rawAcl.BinaryLength];
  49. rawAcl.GetBinaryForm (binaryForm, 0);
  50. rawAcl = new RawAcl (binaryForm, 0);
  51. }
  52. Init (isContainer, isDS, rawAcl);
  53. }
  54. internal CommonAcl (bool isContainer, bool isDS, byte revision, int capacity)
  55. {
  56. Init (isContainer, isDS, new RawAcl (revision, capacity));
  57. }
  58. internal CommonAcl (bool isContainer, bool isDS, int capacity)
  59. : this (isContainer, isDS, isDS ? AclRevisionDS : AclRevision, capacity)
  60. {
  61. }
  62. void Init (bool isContainer, bool isDS, RawAcl rawAcl)
  63. {
  64. is_container = isContainer;
  65. is_ds = isDS;
  66. raw_acl = rawAcl;
  67. CleanAndRetestCanonicity ();
  68. }
  69. bool is_canonical, is_container, is_ds;
  70. internal RawAcl raw_acl;
  71. public override sealed int BinaryLength {
  72. get { return raw_acl.BinaryLength; }
  73. }
  74. public override sealed int Count {
  75. get { return raw_acl.Count; }
  76. }
  77. public bool IsCanonical {
  78. get { return is_canonical; }
  79. }
  80. public bool IsContainer {
  81. get { return is_container; }
  82. }
  83. public bool IsDS {
  84. get { return is_ds; }
  85. }
  86. public override sealed byte Revision {
  87. get { return raw_acl.Revision; }
  88. }
  89. public override sealed GenericAce this[int index] {
  90. get { return raw_acl [index]; }
  91. set { throw new NotSupportedException (); }
  92. }
  93. public override sealed void GetBinaryForm (byte[] binaryForm, int offset)
  94. {
  95. raw_acl.GetBinaryForm (binaryForm, offset);
  96. }
  97. public void Purge (SecurityIdentifier sid)
  98. {
  99. if (!IsCanonical)
  100. throw new InvalidOperationException ();
  101. // Custom ACEs are not canonical.
  102. RemoveAces (ace => ((KnownAce)ace).SecurityIdentifier == sid);
  103. }
  104. public void RemoveInheritedAces ()
  105. {
  106. if (!IsCanonical)
  107. throw new InvalidOperationException();
  108. RemoveAces (ace => ace.IsInherited);
  109. }
  110. internal void CleanAndRetestCanonicity ()
  111. {
  112. RemoveAces (IsAceMeaningless);
  113. is_canonical = TestCanonicity ();
  114. if (IsCanonical) {
  115. ApplyCanonicalSortToExplicitAces ();
  116. MergeExplicitAces ();
  117. }
  118. }
  119. internal virtual bool IsAceMeaningless (GenericAce ace)
  120. {
  121. AceFlags flags = ace.AceFlags;
  122. KnownAce knownAce = ace as KnownAce;
  123. if (knownAce != null) {
  124. if (0 == knownAce.AccessMask) return true;
  125. if (0 != (flags & AceFlags.InheritOnly)) {
  126. if (knownAce is ObjectAce) return true;
  127. if (!IsContainer) return true;
  128. if (0 == (flags & (AceFlags.ContainerInherit|AceFlags.ObjectInherit))) return true;
  129. }
  130. }
  131. return false;
  132. }
  133. bool TestCanonicity ()
  134. {
  135. foreach (GenericAce ace in this) {
  136. if (!(ace is QualifiedAce)) return false;
  137. }
  138. bool gotInheritedAce = false;
  139. foreach (QualifiedAce ace in this) {
  140. if (ace.IsInherited) {
  141. gotInheritedAce = true;
  142. } else {
  143. if (gotInheritedAce) return false;
  144. }
  145. }
  146. bool gotExplicitAllow = false;
  147. foreach (QualifiedAce ace in this) {
  148. if (ace.IsInherited) break;
  149. if (AceQualifier.AccessAllowed == ace.AceQualifier) {
  150. gotExplicitAllow = true;
  151. } else if (AceQualifier.AccessDenied == ace.AceQualifier) {
  152. if (gotExplicitAllow) return false;
  153. }
  154. }
  155. return true;
  156. }
  157. internal int GetCanonicalExplicitDenyAceCount ()
  158. {
  159. int i;
  160. for (i = 0; i < Count; i ++) {
  161. if (this [i].IsInherited) break;
  162. QualifiedAce ace = this [i] as QualifiedAce;
  163. if (ace == null || ace.AceQualifier != AceQualifier.AccessDenied) break;
  164. }
  165. return i;
  166. }
  167. internal int GetCanonicalExplicitAceCount ()
  168. {
  169. int i;
  170. for (i = 0; i < Count; i ++)
  171. if (this [i].IsInherited) break;
  172. return i;
  173. }
  174. void MergeExplicitAces ()
  175. {
  176. int explicitCount = GetCanonicalExplicitAceCount ();
  177. for (int i = 0; i < explicitCount - 1; ) {
  178. GenericAce mergedAce = MergeExplicitAcePair (raw_acl [i], raw_acl [i + 1]);
  179. if (null != mergedAce) {
  180. raw_acl [i] = mergedAce;
  181. raw_acl.RemoveAce (i + 1);
  182. explicitCount --;
  183. } else {
  184. i ++;
  185. }
  186. }
  187. }
  188. GenericAce MergeExplicitAcePair (GenericAce ace1, GenericAce ace2)
  189. {
  190. QualifiedAce qace1 = ace1 as QualifiedAce;
  191. QualifiedAce qace2 = ace2 as QualifiedAce;
  192. if (!(null != qace1 && null != qace2)) return null;
  193. if (!(qace1.AceFlags == qace2.AceFlags && qace1.AceQualifier == qace2.AceQualifier)) return null;
  194. if (!(qace1.SecurityIdentifier == qace2.SecurityIdentifier)) return null;
  195. CommonAce cace1 = ace1 as CommonAce;
  196. CommonAce cace2 = ace2 as CommonAce;
  197. if (null != cace1 && null != cace2) {
  198. return new CommonAce (cace1.AceFlags, cace1.AceQualifier, cace1.AccessMask|cace2.AccessMask,
  199. cace1.SecurityIdentifier, cace1.IsCallback, cace1.GetOpaque());
  200. }
  201. ObjectAce oace1 = ace1 as ObjectAce;
  202. ObjectAce oace2 = ace2 as ObjectAce;
  203. if (null != oace1 && null != oace2) {
  204. // See DiscretionaryAclTest.GuidEmptyMergesRegardlessOfFlagsAndOpaqueDataIsNotConsidered
  205. Guid type1, inheritedType1; GetObjectAceTypeGuids(oace1, out type1, out inheritedType1);
  206. Guid type2, inheritedType2; GetObjectAceTypeGuids(oace2, out type2, out inheritedType2);
  207. if (type1 == type2 && inheritedType1 == inheritedType2) {
  208. return new ObjectAce (oace1.AceFlags, oace1.AceQualifier, oace1.AccessMask|oace2.AccessMask,
  209. oace1.SecurityIdentifier,
  210. oace1.ObjectAceFlags, oace1.ObjectAceType, oace1.InheritedObjectAceType,
  211. oace1.IsCallback, oace1.GetOpaque());
  212. }
  213. }
  214. return null;
  215. }
  216. static void GetObjectAceTypeGuids(ObjectAce ace, out Guid type, out Guid inheritedType)
  217. {
  218. type = Guid.Empty; inheritedType = Guid.Empty;
  219. if (0 != (ace.ObjectAceFlags & ObjectAceFlags.ObjectAceTypePresent))
  220. type = ace.ObjectAceType;
  221. if (0 != (ace.ObjectAceFlags & ObjectAceFlags.InheritedObjectAceTypePresent))
  222. inheritedType = ace.InheritedObjectAceType;
  223. }
  224. internal abstract void ApplyCanonicalSortToExplicitAces ();
  225. internal void ApplyCanonicalSortToExplicitAces (int start, int count)
  226. {
  227. int i, j;
  228. for (i = start + 1; i < start + count; i ++)
  229. {
  230. KnownAce ace = (KnownAce)raw_acl [i];
  231. SecurityIdentifier sid = ace.SecurityIdentifier;
  232. for (j = i; j > start && ((KnownAce)raw_acl [j - 1]).SecurityIdentifier.CompareTo (sid) > 0; j --)
  233. raw_acl [j] = raw_acl [j - 1];
  234. raw_acl [j] = ace;
  235. }
  236. }
  237. internal override string GetSddlForm (ControlFlags sdFlags, bool isDacl)
  238. {
  239. return raw_acl.GetSddlForm (sdFlags, isDacl);
  240. }
  241. void RemoveAces (RemoveAcesCallback callback)
  242. {
  243. for (int i = 0; i < raw_acl.Count; ) {
  244. if (callback (raw_acl [i])) {
  245. raw_acl.RemoveAce (i);
  246. } else {
  247. i ++;
  248. }
  249. }
  250. }
  251. }
  252. }