Fix watchos tests for system.data (#6600)
[mono-project.git] / mcs / class / corlib / System.Security.AccessControl / CommonAcl.cs
blobae6f702090118285b05a138366925c7d4d051a39
1 //
2 // System.Security.AccessControl.CommonAcl implementation
3 //
4 // Authors:
5 // Dick Porter <dick@ximian.com>
6 // Atsushi Enomoto <atsushi@ximian.com>
7 // James Bellinger <jfb@zer7.com>
8 //
9 // Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
10 // Copyright (C) 2012 James Bellinger
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.
32 using System.Collections.Generic;
33 using System.Security.Principal;
35 namespace System.Security.AccessControl
37 /* NB: Note the Remarks section in the CommonAcl class docs
38 * concerning ACE management
40 public abstract class CommonAcl : GenericAcl
42 const int default_capacity = 10; // FIXME: not verified
44 internal delegate bool RemoveAcesCallback<T> (T ace);
46 internal CommonAcl (bool isContainer, bool isDS, RawAcl rawAcl)
48 if (rawAcl == null) {
49 rawAcl = new RawAcl (isDS ? AclRevisionDS : AclRevision, default_capacity);
50 } else {
51 // The RawAcl ACEs are cloned.
52 byte[] binaryForm = new byte [rawAcl.BinaryLength];
53 rawAcl.GetBinaryForm (binaryForm, 0);
54 rawAcl = new RawAcl (binaryForm, 0);
57 Init (isContainer, isDS, rawAcl);
60 internal CommonAcl (bool isContainer, bool isDS, byte revision, int capacity)
62 Init (isContainer, isDS, new RawAcl (revision, capacity));
65 internal CommonAcl (bool isContainer, bool isDS, int capacity)
66 : this (isContainer, isDS, isDS ? AclRevisionDS : AclRevision, capacity)
70 void Init (bool isContainer, bool isDS, RawAcl rawAcl)
72 is_container = isContainer;
73 is_ds = isDS;
74 raw_acl = rawAcl;
75 CanonicalizeAndClearAefa ();
78 bool is_aefa, is_canonical, is_container, is_ds;
79 internal RawAcl raw_acl;
81 public override sealed int BinaryLength {
82 get { return raw_acl.BinaryLength; }
85 public override sealed int Count {
86 get { return raw_acl.Count; }
89 public bool IsCanonical {
90 get { return is_canonical; }
93 public bool IsContainer {
94 get { return is_container; }
97 public bool IsDS {
98 get { return is_ds; }
101 // See CommonSecurityDescriptorTest's AefaModifiedFlagIsStoredOnDiscretionaryAcl unit test.
102 internal bool IsAefa {
103 get { return is_aefa; }
104 set { is_aefa = value; }
107 public override sealed byte Revision {
108 get { return raw_acl.Revision; }
111 public override sealed GenericAce this[int index] {
112 get { return CopyAce (raw_acl [index]); }
113 set { throw new NotSupportedException (); }
116 public override sealed void GetBinaryForm (byte[] binaryForm, int offset)
118 raw_acl.GetBinaryForm (binaryForm, offset);
121 public void Purge (SecurityIdentifier sid)
123 RequireCanonicity ();
124 RemoveAces<KnownAce> (ace => ace.SecurityIdentifier == sid);
127 public void RemoveInheritedAces ()
129 RequireCanonicity ();
130 RemoveAces<GenericAce> (ace => ace.IsInherited);
133 internal void RequireCanonicity ()
135 if (!IsCanonical)
136 throw new InvalidOperationException("ACL is not canonical.");
139 internal void CanonicalizeAndClearAefa ()
141 RemoveAces<GenericAce> (IsAceMeaningless);
143 is_canonical = TestCanonicity ();
145 if (IsCanonical) {
146 ApplyCanonicalSortToExplicitAces ();
147 MergeExplicitAces ();
150 IsAefa = false;
153 internal virtual bool IsAceMeaningless (GenericAce ace)
155 AceFlags flags = ace.AceFlags;
157 KnownAce knownAce = ace as KnownAce;
158 if (knownAce != null) {
159 if (0 == knownAce.AccessMask) return true;
160 if (0 != (flags & AceFlags.InheritOnly)) {
161 if (knownAce is ObjectAce) return true;
162 if (!IsContainer) return true;
163 if (0 == (flags & (AceFlags.ContainerInherit|AceFlags.ObjectInherit))) return true;
167 return false;
170 bool TestCanonicity ()
172 foreach (GenericAce ace in this) {
173 if (!(ace is QualifiedAce)) return false;
176 bool gotInheritedAce = false;
177 foreach (QualifiedAce ace in this) {
178 if (ace.IsInherited) {
179 gotInheritedAce = true;
180 } else {
181 if (gotInheritedAce) return false;
185 bool gotExplicitAllow = false;
186 foreach (QualifiedAce ace in this) {
187 if (ace.IsInherited) break;
188 if (AceQualifier.AccessAllowed == ace.AceQualifier) {
189 gotExplicitAllow = true;
190 } else if (AceQualifier.AccessDenied == ace.AceQualifier) {
191 if (gotExplicitAllow) return false;
195 return true;
198 internal int GetCanonicalExplicitDenyAceCount ()
200 int i;
201 for (i = 0; i < Count; i ++) {
202 if (raw_acl [i].IsInherited) break;
204 QualifiedAce ace = raw_acl [i] as QualifiedAce;
205 if (ace == null || ace.AceQualifier != AceQualifier.AccessDenied) break;
207 return i;
210 internal int GetCanonicalExplicitAceCount ()
212 int i;
213 for (i = 0; i < Count; i ++)
214 if (raw_acl [i].IsInherited) break;
215 return i;
218 void MergeExplicitAces ()
220 int explicitCount = GetCanonicalExplicitAceCount ();
222 for (int i = 0; i < explicitCount - 1; ) {
223 GenericAce mergedAce = MergeExplicitAcePair (raw_acl [i], raw_acl [i + 1]);
224 if (null != mergedAce) {
225 raw_acl [i] = mergedAce;
226 raw_acl.RemoveAce (i + 1);
227 explicitCount --;
228 } else {
229 i ++;
234 GenericAce MergeExplicitAcePair (GenericAce ace1, GenericAce ace2)
236 QualifiedAce qace1 = ace1 as QualifiedAce;
237 QualifiedAce qace2 = ace2 as QualifiedAce;
238 if (!(null != qace1 && null != qace2)) return null;
239 if (!(qace1.AceQualifier == qace2.AceQualifier)) return null;
240 if (!(qace1.SecurityIdentifier == qace2.SecurityIdentifier)) return null;
242 AceFlags aceFlags1 = qace1.AceFlags, aceFlags2 = qace2.AceFlags, aceFlagsNew;
243 int accessMask1 = qace1.AccessMask, accessMask2 = qace2.AccessMask, accessMaskNew;
245 if (!IsContainer) {
246 aceFlags1 &= ~AceFlags.InheritanceFlags;
247 aceFlags2 &= ~AceFlags.InheritanceFlags;
250 if (aceFlags1 != aceFlags2) {
251 if (accessMask1 != accessMask2) return null;
252 if ((aceFlags1 & ~(AceFlags.ContainerInherit|AceFlags.ObjectInherit)) ==
253 (aceFlags2 & ~(AceFlags.ContainerInherit|AceFlags.ObjectInherit))) {
254 aceFlagsNew = aceFlags1|aceFlags2; // merge InheritanceFlags
255 accessMaskNew = accessMask1;
256 } else if ((aceFlags1 & ~(AceFlags.SuccessfulAccess|AceFlags.FailedAccess)) ==
257 (aceFlags2 & ~(AceFlags.SuccessfulAccess|AceFlags.FailedAccess))) {
258 aceFlagsNew = aceFlags1|aceFlags2; // merge AuditFlags
259 accessMaskNew = accessMask1;
260 } else {
261 return null;
263 } else {
264 aceFlagsNew = aceFlags1;
265 accessMaskNew = accessMask1|accessMask2;
268 CommonAce cace1 = ace1 as CommonAce;
269 CommonAce cace2 = ace2 as CommonAce;
270 if (null != cace1 && null != cace2) {
271 return new CommonAce (aceFlagsNew, cace1.AceQualifier, accessMaskNew,
272 cace1.SecurityIdentifier, cace1.IsCallback, cace1.GetOpaque());
275 ObjectAce oace1 = ace1 as ObjectAce;
276 ObjectAce oace2 = ace2 as ObjectAce;
277 if (null != oace1 && null != oace2) {
278 // See DiscretionaryAclTest.GuidEmptyMergesRegardlessOfFlagsAndOpaqueDataIsNotConsidered
279 Guid type1, inheritedType1; GetObjectAceTypeGuids(oace1, out type1, out inheritedType1);
280 Guid type2, inheritedType2; GetObjectAceTypeGuids(oace2, out type2, out inheritedType2);
282 if (type1 == type2 && inheritedType1 == inheritedType2) {
283 return new ObjectAce (aceFlagsNew, oace1.AceQualifier, accessMaskNew,
284 oace1.SecurityIdentifier,
285 oace1.ObjectAceFlags, oace1.ObjectAceType, oace1.InheritedObjectAceType,
286 oace1.IsCallback, oace1.GetOpaque());
290 return null;
293 static void GetObjectAceTypeGuids(ObjectAce ace, out Guid type, out Guid inheritedType)
295 type = Guid.Empty; inheritedType = Guid.Empty;
296 if (0 != (ace.ObjectAceFlags & ObjectAceFlags.ObjectAceTypePresent))
297 type = ace.ObjectAceType;
298 if (0 != (ace.ObjectAceFlags & ObjectAceFlags.InheritedObjectAceTypePresent))
299 inheritedType = ace.InheritedObjectAceType;
302 internal abstract void ApplyCanonicalSortToExplicitAces ();
304 internal void ApplyCanonicalSortToExplicitAces (int start, int count)
306 int i, j;
307 for (i = start + 1; i < start + count; i ++)
309 KnownAce ace = (KnownAce)raw_acl [i];
310 SecurityIdentifier sid = ace.SecurityIdentifier;
311 for (j = i; j > start && ((KnownAce)raw_acl [j - 1]).SecurityIdentifier.CompareTo (sid) > 0; j --)
312 raw_acl [j] = raw_acl [j - 1];
313 raw_acl [j] = ace;
317 internal override string GetSddlForm (ControlFlags sdFlags, bool isDacl)
319 return raw_acl.GetSddlForm (sdFlags, isDacl);
322 internal void RemoveAces<T> (RemoveAcesCallback<T> callback)
323 where T : GenericAce
325 for (int i = 0; i < raw_acl.Count; ) {
326 if (raw_acl [i] is T && callback ((T)raw_acl [i])) {
327 raw_acl.RemoveAce (i);
328 } else {
329 i ++;
334 // DiscretionaryAcl/SystemAcl shared implementation below...
335 internal void AddAce (AceQualifier aceQualifier,
336 SecurityIdentifier sid, int accessMask,
337 InheritanceFlags inheritanceFlags,
338 PropagationFlags propagationFlags,
339 AuditFlags auditFlags)
341 QualifiedAce ace = AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
342 inheritanceFlags, propagationFlags, auditFlags);
343 AddAce (ace);
346 internal void AddAce (AceQualifier aceQualifier,
347 SecurityIdentifier sid, int accessMask,
348 InheritanceFlags inheritanceFlags,
349 PropagationFlags propagationFlags,
350 AuditFlags auditFlags,
351 ObjectAceFlags objectFlags,
352 Guid objectType,
353 Guid inheritedObjectType)
355 QualifiedAce ace = AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
356 inheritanceFlags, propagationFlags, auditFlags,
357 objectFlags, objectType, inheritedObjectType);
358 AddAce (ace);
361 QualifiedAce AddAceGetQualifiedAce (AceQualifier aceQualifier,
362 SecurityIdentifier sid, int accessMask,
363 InheritanceFlags inheritanceFlags,
364 PropagationFlags propagationFlags,
365 AuditFlags auditFlags,
366 ObjectAceFlags objectFlags,
367 Guid objectType,
368 Guid inheritedObjectType)
370 if (!IsDS)
371 throw new InvalidOperationException ("For this overload, IsDS must be true.");
373 if (ObjectAceFlags.None == objectFlags)
374 return AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
375 inheritanceFlags, propagationFlags, auditFlags);
377 AceFlags flags = GetAceFlags (inheritanceFlags, propagationFlags, auditFlags);
378 return new ObjectAce (flags, aceQualifier, accessMask, sid,
379 objectFlags, objectType, inheritedObjectType, false, null);
382 QualifiedAce AddAceGetQualifiedAce (AceQualifier aceQualifier,
383 SecurityIdentifier sid, int accessMask,
384 InheritanceFlags inheritanceFlags,
385 PropagationFlags propagationFlags,
386 AuditFlags auditFlags)
388 AceFlags flags = GetAceFlags (inheritanceFlags, propagationFlags, auditFlags);
389 return new CommonAce (flags, aceQualifier, accessMask, sid, false, null);
392 void AddAce (QualifiedAce newAce)
394 RequireCanonicity ();
396 int pos = GetAceInsertPosition (newAce.AceQualifier);
397 raw_acl.InsertAce (pos, CopyAce (newAce));
398 CanonicalizeAndClearAefa ();
401 static GenericAce CopyAce (GenericAce ace)
403 byte[] binaryForm = new byte[ace.BinaryLength];
404 ace.GetBinaryForm (binaryForm, 0);
405 return GenericAce.CreateFromBinaryForm (binaryForm, 0);
408 internal abstract int GetAceInsertPosition (AceQualifier aceQualifier);
410 AceFlags GetAceFlags (InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags auditFlags)
412 if (InheritanceFlags.None != inheritanceFlags && !IsContainer)
413 throw new ArgumentException ("Flags only work with containers.", "inheritanceFlags");
415 if (InheritanceFlags.None == inheritanceFlags && PropagationFlags.None != propagationFlags)
416 throw new ArgumentException ("Propagation flags need inheritance flags.", "propagationFlags");
418 AceFlags flags = AceFlags.None;
419 if (0 != (InheritanceFlags.ContainerInherit & inheritanceFlags))
420 flags |= AceFlags.ContainerInherit;
421 if (0 != (InheritanceFlags.ObjectInherit & inheritanceFlags))
422 flags |= AceFlags.ObjectInherit;
423 if (0 != (PropagationFlags.InheritOnly & propagationFlags))
424 flags |= AceFlags.InheritOnly;
425 if (0 != (PropagationFlags.NoPropagateInherit & propagationFlags))
426 flags |= AceFlags.NoPropagateInherit;
427 if (0 != (AuditFlags.Success & auditFlags))
428 flags |= AceFlags.SuccessfulAccess;
429 if (0 != (AuditFlags.Failure & auditFlags))
430 flags |= AceFlags.FailedAccess;
431 return flags;
434 internal void RemoveAceSpecific (AceQualifier aceQualifier,
435 SecurityIdentifier sid,
436 int accessMask,
437 InheritanceFlags inheritanceFlags,
438 PropagationFlags propagationFlags,
439 AuditFlags auditFlags)
441 RequireCanonicity ();
442 RemoveAces<CommonAce> (ace =>
444 if (ace.AccessMask != accessMask) return false;
445 if (ace.AceQualifier != aceQualifier) return false;
446 if (ace.SecurityIdentifier != sid) return false;
447 if (ace.InheritanceFlags != inheritanceFlags) return false;
448 if (InheritanceFlags.None != inheritanceFlags)
449 if (ace.PropagationFlags != propagationFlags) return false;
450 if (ace.AuditFlags != auditFlags) return false;
451 return true;
453 CanonicalizeAndClearAefa ();
456 internal void RemoveAceSpecific (AceQualifier aceQualifier,
457 SecurityIdentifier sid,
458 int accessMask,
459 InheritanceFlags inheritanceFlags,
460 PropagationFlags propagationFlags,
461 AuditFlags auditFlags,
462 ObjectAceFlags objectFlags,
463 Guid objectType,
464 Guid inheritedObjectType)
466 if (!IsDS)
467 throw new InvalidOperationException ("For this overload, IsDS must be true.");
469 if (ObjectAceFlags.None == objectFlags) {
470 RemoveAceSpecific (aceQualifier, sid, accessMask, inheritanceFlags, propagationFlags, auditFlags);
471 return;
474 RequireCanonicity ();
475 RemoveAces<ObjectAce> (ace =>
477 if (ace.AccessMask != accessMask) return false;
478 if (ace.AceQualifier != aceQualifier) return false;
479 if (ace.SecurityIdentifier != sid) return false;
480 if (ace.InheritanceFlags != inheritanceFlags) return false;
481 if (InheritanceFlags.None != inheritanceFlags)
482 if (ace.PropagationFlags != propagationFlags) return false;
483 if (ace.AuditFlags != auditFlags) return false;
484 if (ace.ObjectAceFlags != objectFlags) return false;
485 if (0 != (objectFlags & ObjectAceFlags.ObjectAceTypePresent))
486 if (ace.ObjectAceType != objectType) return false;
487 if (0 != (objectFlags & ObjectAceFlags.InheritedObjectAceTypePresent))
488 if (ace.InheritedObjectAceType != objectType) return false;
489 return true;
491 CanonicalizeAndClearAefa ();
494 internal void SetAce (AceQualifier aceQualifier,
495 SecurityIdentifier sid,
496 int accessMask,
497 InheritanceFlags inheritanceFlags,
498 PropagationFlags propagationFlags,
499 AuditFlags auditFlags)
501 QualifiedAce ace = AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
502 inheritanceFlags, propagationFlags, auditFlags);
503 SetAce (ace);
506 internal void SetAce (AceQualifier aceQualifier,
507 SecurityIdentifier sid,
508 int accessMask,
509 InheritanceFlags inheritanceFlags,
510 PropagationFlags propagationFlags,
511 AuditFlags auditFlags,
512 ObjectAceFlags objectFlags,
513 Guid objectType,
514 Guid inheritedObjectType)
516 QualifiedAce ace = AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
517 inheritanceFlags, propagationFlags, auditFlags,
518 objectFlags, objectType, inheritedObjectType);
519 SetAce (ace);
522 void SetAce (QualifiedAce newAce)
524 RequireCanonicity ();
526 RemoveAces<QualifiedAce> (oldAce =>
528 return oldAce.AceQualifier == newAce.AceQualifier &&
529 oldAce.SecurityIdentifier == newAce.SecurityIdentifier;
531 CanonicalizeAndClearAefa ();
533 AddAce (newAce);