Explorar el Código

Implemented all of DiscretionaryAcl except for RemoveAccess. Unit tests are included.

Also fixed:
CommonAcl's merging now filters out AceFlags.InheritedFlags when !IsContainer.
For matching AccessMask, CommonAcl will now correctly merge ContainerInherit and ObjectInherit.
GenericAcl's SyncRoot is now virtual as per spec.
SecurityIdentifier.CompareTo throws ArgumentNullException, not NullReferenceException, on null parameter.

Miscellaneous unit tests:
Verify that RawAcl throws for negative capacity.
James Bellinger hace 13 años
padre
commit
2d415e7a8f

+ 37 - 16
mcs/class/corlib/System.Security.AccessControl/CommonAcl.cs

@@ -41,7 +41,7 @@ namespace System.Security.AccessControl
 	{
 		const int default_capacity = 10; // FIXME: not verified
 
-		delegate bool RemoveAcesCallback (GenericAce ace);
+		internal delegate bool RemoveAcesCallback<T> (T ace);
 
 		internal CommonAcl (bool isContainer, bool isDS, RawAcl rawAcl)
 		{
@@ -114,24 +114,25 @@ namespace System.Security.AccessControl
 		
 		public void Purge (SecurityIdentifier sid)
 		{
-			if (!IsCanonical)
-				throw new InvalidOperationException ();
-
-			// Custom ACEs are not canonical.
-			RemoveAces (ace => ((KnownAce)ace).SecurityIdentifier == sid);
+			RequireCanonicity ();
+			RemoveAces<KnownAce> (ace => ace.SecurityIdentifier == sid);
 		}
 
 		public void RemoveInheritedAces ()
 		{
-			if (!IsCanonical)
-				throw new InvalidOperationException();
-
-			RemoveAces (ace => ace.IsInherited);
+			RequireCanonicity ();
+			RemoveAces<GenericAce> (ace => ace.IsInherited);
 		}
 
+		internal void RequireCanonicity ()
+		{
+			if (!IsCanonical)
+				throw new InvalidOperationException("ACL is not canonical.");
+		}
+		
 		internal void CleanAndRetestCanonicity ()
 		{
-			RemoveAces (IsAceMeaningless);
+			RemoveAces<GenericAce> (IsAceMeaningless);
 
 			is_canonical = TestCanonicity ();
 			
@@ -227,13 +228,32 @@ namespace System.Security.AccessControl
 			QualifiedAce qace1 = ace1 as QualifiedAce;
 			QualifiedAce qace2 = ace2 as QualifiedAce;
 			if (!(null != qace1 && null != qace2)) return null;
-			if (!(qace1.AceFlags == qace2.AceFlags && qace1.AceQualifier == qace2.AceQualifier)) return null;
+			if (!(qace1.AceQualifier == qace2.AceQualifier)) return null;
 			if (!(qace1.SecurityIdentifier == qace2.SecurityIdentifier)) return null;
 			
+			AceFlags aceFlags1 = qace1.AceFlags, aceFlags2 = qace2.AceFlags, aceFlagsNew;
+			int accessMask1 = qace1.AccessMask, accessMask2 = qace2.AccessMask, accessMaskNew;
+			
+			if (!IsContainer) {
+				aceFlags1 &= ~AceFlags.InheritanceFlags;
+				aceFlags2 &= ~AceFlags.InheritanceFlags;
+			}
+			
+			if (aceFlags1 != aceFlags2) {
+				if (accessMask1 != accessMask2) return null;
+				if ((aceFlags1 & ~(AceFlags.ContainerInherit|AceFlags.ObjectInherit)) !=
+				    (aceFlags2 & ~(AceFlags.ContainerInherit|AceFlags.ObjectInherit))) return null;
+				aceFlagsNew = aceFlags1|aceFlags2;
+				accessMaskNew = accessMask1;
+			} else {
+				aceFlagsNew = aceFlags1;
+				accessMaskNew = accessMask1|accessMask2;
+			}
+			
 			CommonAce cace1 = ace1 as CommonAce;
 			CommonAce cace2 = ace2 as CommonAce;
 			if (null != cace1 && null != cace2) {
-				return new CommonAce (cace1.AceFlags, cace1.AceQualifier, cace1.AccessMask|cace2.AccessMask,
+				return new CommonAce (aceFlagsNew, cace1.AceQualifier, accessMaskNew,
 					cace1.SecurityIdentifier, cace1.IsCallback, cace1.GetOpaque());
 			}
 			
@@ -245,7 +265,7 @@ namespace System.Security.AccessControl
 				Guid type2, inheritedType2; GetObjectAceTypeGuids(oace2, out type2, out inheritedType2);
 				
 				if (type1 == type2 && inheritedType1 == inheritedType2) {
-					return new ObjectAce (oace1.AceFlags, oace1.AceQualifier, oace1.AccessMask|oace2.AccessMask,
+					return new ObjectAce (aceFlagsNew, oace1.AceQualifier, accessMaskNew,
 						oace1.SecurityIdentifier,
 						oace1.ObjectAceFlags, oace1.ObjectAceType, oace1.InheritedObjectAceType,
 						oace1.IsCallback, oace1.GetOpaque());
@@ -284,10 +304,11 @@ namespace System.Security.AccessControl
 			return raw_acl.GetSddlForm (sdFlags, isDacl);
 		}
 
-		void RemoveAces (RemoveAcesCallback callback)
+		internal void RemoveAces<T> (RemoveAcesCallback<T> callback)
+			where T : GenericAce
 		{
 			for (int i = 0; i < raw_acl.Count; ) {
-				if (callback (raw_acl [i])) {
+				if (raw_acl [i] is T && callback ((T)raw_acl [i])) {
 					raw_acl.RemoveAce (i);
 				} else {
 					i ++;

+ 143 - 8
mcs/class/corlib/System.Security.AccessControl/DiscretionaryAcl.cs

@@ -4,8 +4,10 @@
 // Authors:
 //	Dick Porter  <[email protected]>
 //	Atsushi Enomoto  <[email protected]>
+//	James Bellinger  <[email protected]>
 //
 // Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2012      James Bellinger
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -53,8 +55,9 @@ namespace System.Security.AccessControl
 				       InheritanceFlags inheritanceFlags,
 				       PropagationFlags propagationFlags)
 		{
-			throw new NotImplementedException ();
-			// CommonAce?
+			QualifiedAce ace = AddAccessGetQualifiedAce (accessType, sid, accessMask,
+								     inheritanceFlags, propagationFlags);
+			AddAccess (ace);
 		}
 		
 		public void AddAccess (AccessControlType accessType,
@@ -65,8 +68,54 @@ namespace System.Security.AccessControl
 				       Guid objectType,
 				       Guid inheritedObjectType)
 		{
-			// ObjectAce?
-			throw new NotImplementedException ();
+			QualifiedAce ace = AddAccessGetQualifiedAce (accessType, sid, accessMask,
+								     inheritanceFlags, propagationFlags,
+								     objectFlags, objectType, inheritedObjectType);
+			AddAccess (ace);
+		}
+
+		QualifiedAce AddAccessGetQualifiedAce (AccessControlType accessType,
+						       SecurityIdentifier sid, int accessMask,
+						       InheritanceFlags inheritanceFlags,
+						       PropagationFlags propagationFlags,
+						       ObjectAceFlags objectFlags,
+						       Guid objectType,
+						       Guid inheritedObjectType)
+		{
+			if (!IsDS)
+				throw new InvalidOperationException ("For this overload, IsDS must be true.");
+				
+			if (ObjectAceFlags.None == objectFlags)
+				return AddAccessGetQualifiedAce (accessType, sid, accessMask, inheritanceFlags, propagationFlags);
+			
+			AceQualifier qualifier = GetAceQualifier (accessType);
+			AceFlags flags = GetAceFlags (inheritanceFlags, propagationFlags);
+			return new ObjectAce (flags, qualifier, accessMask, sid,
+					      objectFlags, objectType, inheritedObjectType, false, null);
+		}
+		
+		QualifiedAce AddAccessGetQualifiedAce (AccessControlType accessType,
+						       SecurityIdentifier sid, int accessMask,
+						       InheritanceFlags inheritanceFlags,
+						       PropagationFlags propagationFlags)
+		{
+			AceQualifier qualifier = GetAceQualifier (accessType);
+			AceFlags flags = GetAceFlags (inheritanceFlags, propagationFlags);
+			return new CommonAce (flags, qualifier, accessMask, sid, false, null);
+		}
+		
+		void AddAccess (QualifiedAce newAce)
+		{
+			RequireCanonicity ();
+				
+			int pos; // Canonical order is explicit deny, explicit allow, inherited.
+			if (AceQualifier.AccessAllowed == newAce.AceQualifier)
+				pos = GetCanonicalExplicitDenyAceCount ();
+			else
+				pos = 0;
+			
+			raw_acl.InsertAce (pos, newAce);
+			CleanAndRetestCanonicity ();
 		}
 		
 		public bool RemoveAccess (AccessControlType accessType,
@@ -96,7 +145,19 @@ namespace System.Security.AccessControl
 						  InheritanceFlags inheritanceFlags,
 						  PropagationFlags propagationFlags)
 		{
-			throw new NotImplementedException ();
+			RequireCanonicity ();
+			AceQualifier qualifier = GetAceQualifier (accessType);
+			RemoveAces<CommonAce> (ace =>
+			{
+				if (ace.AccessMask != accessMask) return false;
+				if (ace.AceQualifier != qualifier) return false;
+				if (ace.SecurityIdentifier != sid) return false;
+				if (ace.InheritanceFlags != inheritanceFlags) return false;
+				if (InheritanceFlags.None != inheritanceFlags)
+					if (ace.PropagationFlags != propagationFlags) return false;
+				return true;
+			});
+			CleanAndRetestCanonicity ();
 		}
 		
 		public void RemoveAccessSpecific (AccessControlType accessType,
@@ -108,7 +169,32 @@ namespace System.Security.AccessControl
 						  Guid objectType,
 						  Guid inheritedObjectType)
 		{
-			throw new NotImplementedException ();
+			if (!IsDS)
+				throw new InvalidOperationException ("For this overload, IsDS must be true.");
+				
+			if (ObjectAceFlags.None == objectFlags) {
+				RemoveAccessSpecific (accessType, sid, accessMask, inheritanceFlags, propagationFlags);
+				return;
+			}
+
+			RequireCanonicity ();
+			AceQualifier qualifier = GetAceQualifier (accessType);
+			RemoveAces<ObjectAce> (ace =>
+			{
+				if (ace.AccessMask != accessMask) return false;
+				if (ace.AceQualifier != qualifier) return false;
+				if (ace.SecurityIdentifier != sid) return false;
+				if (ace.InheritanceFlags != inheritanceFlags) return false;
+				if (InheritanceFlags.None != inheritanceFlags)
+					if (ace.PropagationFlags != propagationFlags) return false;
+				if (ace.ObjectAceFlags != objectFlags) return false;
+				if (0 != (objectFlags & ObjectAceFlags.ObjectAceTypePresent))
+					if (ace.ObjectAceType != objectType) return false;
+				if (0 != (objectFlags & ObjectAceFlags.InheritedObjectAceTypePresent))
+					if (ace.InheritedObjectAceType != objectType) return false;
+				return true;
+			});
+			CleanAndRetestCanonicity ();
 		}
 		
 		public void SetAccess (AccessControlType accessType,
@@ -117,7 +203,9 @@ namespace System.Security.AccessControl
 				       InheritanceFlags inheritanceFlags,
 				       PropagationFlags propagationFlags)
 		{
-			throw new NotImplementedException ();
+			QualifiedAce ace = AddAccessGetQualifiedAce (accessType, sid, accessMask,
+								     inheritanceFlags, propagationFlags);
+			SetAccess (ace);
 		}
 		
 		public void SetAccess (AccessControlType accessType,
@@ -129,7 +217,24 @@ namespace System.Security.AccessControl
 				       Guid objectType,
 				       Guid inheritedObjectType)
 		{
-			throw new NotImplementedException ();
+			QualifiedAce ace = AddAccessGetQualifiedAce (accessType, sid, accessMask,
+								     inheritanceFlags, propagationFlags,
+								     objectFlags, objectType, inheritedObjectType);
+			SetAccess (ace);
+		}
+
+		void SetAccess (QualifiedAce newAce)
+		{
+			RequireCanonicity ();
+			
+			RemoveAces<QualifiedAce> (oldAce =>
+			{
+				return oldAce.AceQualifier == newAce.AceQualifier &&
+				       oldAce.SecurityIdentifier == newAce.SecurityIdentifier;
+			});
+			CleanAndRetestCanonicity ();
+						
+			AddAccess (newAce);
 		}
 
 		internal override void ApplyCanonicalSortToExplicitAces ()
@@ -153,6 +258,36 @@ namespace System.Security.AccessControl
 
 			return false;
 		}
+		
+		AceFlags GetAceFlags (InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags)
+		{
+			if (InheritanceFlags.None != inheritanceFlags && !IsContainer)
+				throw new ArgumentException ("Flags only work with containers.", "inheritanceFlags");
+			
+			if (InheritanceFlags.None == inheritanceFlags && PropagationFlags.None != propagationFlags)
+				throw new ArgumentException ("Propagation flags need inheritance flags.", "propagationFlags");
+			
+			AceFlags flags = AceFlags.None;
+			if (0 != ((InheritanceFlags.ContainerInherit) & inheritanceFlags))
+				flags |= AceFlags.ContainerInherit;
+			if (0 != ((InheritanceFlags.ObjectInherit) & inheritanceFlags))
+				flags |= AceFlags.ObjectInherit;
+			if (0 != ((PropagationFlags.InheritOnly) & propagationFlags))
+				flags |= AceFlags.InheritOnly;
+			if (0 != ((PropagationFlags.NoPropagateInherit) & propagationFlags))
+				flags |= AceFlags.NoPropagateInherit;
+			return flags;
+		}
+		
+		static AceQualifier GetAceQualifier (AccessControlType accessType)
+		{
+			if (AccessControlType.Allow == accessType)
+				return AceQualifier.AccessAllowed;
+			else if (AccessControlType.Deny == accessType)
+				return AceQualifier.AccessDenied;
+			else
+				throw new ArgumentOutOfRangeException ("accessType");
+		}
 	}
 }
 

+ 1 - 1
mcs/class/corlib/System.Security.AccessControl/GenericAcl.cs

@@ -63,7 +63,7 @@ namespace System.Security.AccessControl {
 		
 		public abstract byte Revision { get; }
 		
-		public object SyncRoot {
+		public virtual object SyncRoot {
 			get { return this; }
 		}
 		

+ 3 - 1
mcs/class/corlib/System.Security.Principal/SecurityIdentifier.cs

@@ -41,7 +41,6 @@ namespace System.Security.Principal {
 		public static readonly int MaxBinaryLength = 68;
 		public static readonly int MinBinaryLength = 8;
 
-
 		public SecurityIdentifier (string sddlForm)
 		{
 			if (sddlForm == null)
@@ -155,6 +154,9 @@ namespace System.Security.Principal {
 		// The comparison was determined to be: authority, then subauthority count, then subauthority.
 		public int CompareTo (SecurityIdentifier sid)
 		{
+			if (sid == null)
+				throw new ArgumentNullException ("sid");
+				
 			int result;
 			if (0 != (result = GetSidAuthority ().CompareTo (sid.GetSidAuthority ()))) return result;
 			if (0 != (result = GetSidSubAuthorityCount ().CompareTo (sid.GetSidSubAuthorityCount ()))) return result;

+ 50 - 2
mcs/class/corlib/Test/System.Security.AccessControl/CommonAclTest.cs

@@ -363,11 +363,59 @@ namespace MonoTests.System.Security.AccessControl
 			return acl;
 		}
 
-		static ushort ToUInt16(byte[] buffer, int offset)
+		static ushort ToUInt16 (byte[] buffer, int offset)
 		{
 			return (ushort)(buffer [offset] | buffer [offset + 1]);
 		}
+
+		[Test]
+		public void InheritanceFlagsMergeForAccessMasksThatMatch ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BU");
+
+			RawAcl acl = MakeRawAcl (new GenericAce[] {
+				new CommonAce (AceFlags.ContainerInherit, AceQualifier.AccessAllowed, 1, sid, false, null),
+				new CommonAce (AceFlags.ObjectInherit, AceQualifier.AccessAllowed, 1, sid, false, null)
+			});
+
+			DiscretionaryAcl dacl = new DiscretionaryAcl (true, false, acl);
+			Assert.AreEqual (1, dacl.Count);
+
+			CommonAce ace = (CommonAce) dacl [0];
+			Assert.AreEqual (InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, ace.InheritanceFlags);
+		}
+
+		[Test]
+		public void InheritanceFlagsDoNotMergeForAccessMasksThatAND ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BU");
+
+			RawAcl acl = MakeRawAcl (new GenericAce[] {
+				new CommonAce (AceFlags.ContainerInherit, AceQualifier.AccessAllowed, 1, sid, false, null),
+				new CommonAce (AceFlags.ObjectInherit, AceQualifier.AccessAllowed, 3, sid, false, null)
+			});
+
+			DiscretionaryAcl dacl = new DiscretionaryAcl (true, false, acl);
+			Assert.AreEqual (2, dacl.Count);
+		}
+
+		[Test]
+		public void InheritanceFlagsAreClearedBeforeMergeCheckingWhenNotContainer ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BU");
+
+			RawAcl acl = MakeRawAcl (new GenericAce[] {
+				new CommonAce (AceFlags.ContainerInherit, AceQualifier.AccessAllowed, 1, sid, false, null),
+				new CommonAce (AceFlags.ObjectInherit, AceQualifier.AccessAllowed, 2, sid, false, null)
+			});
+
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
+			Assert.AreEqual (1, dacl.Count);
+
+			CommonAce ace = (CommonAce) dacl [0];
+			Assert.AreEqual (3, ace.AccessMask);
+			Assert.AreEqual (InheritanceFlags.None, ace.InheritanceFlags);
+		}
 	}
 }
 
-

+ 249 - 0
mcs/class/corlib/Test/System.Security.AccessControl/DiscretionaryAclTest.cs

@@ -0,0 +1,249 @@
+// DiscretionaryAclTest.cs - NUnit Test Cases for DiscretionaryAcl
+//
+// Authors:
+//	James Bellinger  <[email protected]>
+//
+// Copyright (C) 2012 James Bellinger
+
+using System;
+using System.Collections.Generic;
+using System.Security.AccessControl;
+using System.Security.Principal;
+using NUnit.Framework;
+
+namespace MonoTests.System.Security.AccessControl
+{
+	[TestFixture]
+	public class DiscretionaryAclTest
+	{
+		[Test]
+		public void StartsEmpty ()
+		{
+			Assert.AreEqual (0, new DiscretionaryAcl (false, false, 0).Count);
+			Assert.AreEqual (0, new DiscretionaryAcl (false, false, null).Count);
+
+		}
+
+		[Test]
+		public void AddAccessCommonAce ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BA");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, 0);
+
+			dacl.AddAccess (AccessControlType.Allow, sid, 1, InheritanceFlags.None, PropagationFlags.None);
+			Assert.AreEqual (1, dacl.Count);
+
+			CommonAce ace = (CommonAce)dacl[0];
+			Assert.AreEqual (1, ace.AccessMask);
+			Assert.AreEqual ("S-1-5-32-544", ace.SecurityIdentifier.Value);
+			Assert.IsFalse (ace.IsInherited);
+		}
+
+		[Test]
+		public void AddAccessCommonAceUsingDSOverload ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BA");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, true, 0);
+
+			dacl.AddAccess (AccessControlType.Allow, sid, 1, InheritanceFlags.None, PropagationFlags.None,
+			                ObjectAceFlags.None, Guid.NewGuid (), Guid.NewGuid ());
+			Assert.AreEqual (1, dacl.Count);
+
+			CommonAce ace = (CommonAce)dacl [0];
+			Assert.AreEqual (1, ace.AccessMask);
+			Assert.AreEqual ("S-1-5-32-544", ace.SecurityIdentifier.Value);
+			Assert.IsFalse (ace.IsInherited);
+		}
+
+		[Test, ExpectedException (typeof (InvalidOperationException))]
+		public void AddAccessObjectAceNonDSFailsEvenIfObjectAceFlagsNoneImplyingCommonAce ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BA");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, 0);
+
+			dacl.AddAccess (AccessControlType.Allow, sid, 1, InheritanceFlags.None, PropagationFlags.None,
+			                ObjectAceFlags.None, Guid.Empty, Guid.Empty);
+		}
+
+		[Test, ExpectedException (typeof (InvalidOperationException))]
+		public void AddAccessFailsOnNonCanonical ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BU");
+
+			RawAcl acl = new RawAcl (RawAcl.AclRevision, 0);
+			acl.InsertAce (0, new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 1, sid, false, null));
+			acl.InsertAce (1, new CommonAce (AceFlags.None, AceQualifier.AccessDenied, 1, sid, false, null));
+
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
+			Assert.IsFalse (dacl.IsCanonical);
+			Assert.AreEqual (2, dacl.Count);
+
+			dacl.AddAccess (AccessControlType.Allow, sid, 1, InheritanceFlags.None, PropagationFlags.None);
+		}
+
+		[Test, ExpectedException (typeof (ArgumentException))]
+		public void InheritanceFlagsRequireContainer ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BU");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, 0);
+			dacl.AddAccess (AccessControlType.Allow, sid, 3, InheritanceFlags.ContainerInherit, PropagationFlags.None);
+		}
+
+		[Test, ExpectedException (typeof (ArgumentException))]
+		public void PropagationFlagsRequireInheritanceFlagsForAdd ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BU");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (true, false, 0);
+			dacl.AddAccess (AccessControlType.Allow, sid, 3, InheritanceFlags.None, PropagationFlags.InheritOnly);
+		}
+
+		[Test]
+		public void AddAccessObjectAceAndCommonAce ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BA");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, true, 0);
+
+			dacl.AddAccess (AccessControlType.Allow, sid, 1, InheritanceFlags.None, PropagationFlags.None,
+			                ObjectAceFlags.ObjectAceTypePresent, Guid.NewGuid (), Guid.Empty);
+			dacl.AddAccess (AccessControlType.Allow, sid, 1, InheritanceFlags.None, PropagationFlags.None,
+					ObjectAceFlags.None, Guid.Empty, Guid.Empty);
+			Assert.AreEqual (2, dacl.Count);
+
+			CommonAce cace = (CommonAce)dacl [0];
+			Assert.AreEqual (1, cace.AccessMask);
+			Assert.AreEqual ("S-1-5-32-544", cace.SecurityIdentifier.Value);
+			Assert.IsFalse (cace.IsCallback);
+			Assert.IsFalse (cace.IsInherited);
+
+			ObjectAce oace = (ObjectAce)dacl [1];
+			Assert.AreEqual (1, oace.AccessMask);
+			Assert.AreEqual ("S-1-5-32-544", oace.SecurityIdentifier.Value);
+			Assert.IsFalse (oace.IsCallback);
+			Assert.IsFalse (oace.IsInherited);
+
+			dacl.AddAccess (AccessControlType.Allow, sid, 2, InheritanceFlags.None, PropagationFlags.None,
+					ObjectAceFlags.None, Guid.Empty, Guid.Empty);
+			Assert.AreEqual (2, dacl.Count);
+
+			CommonAce cace2 = (CommonAce)dacl [0];
+			Assert.AreEqual (3, cace2.AccessMask);
+		}
+
+		[Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
+		public void InvalidAccessControlType ()
+		{
+			// This is also testing the fact that the AccessControlType is checked before the
+			// InheritanceFlags are validated -- IsContainer is false here, so if the InheritanceFlags
+			// were checked first, ArgumentException would be thrown instead.
+			SecurityIdentifier sid = new SecurityIdentifier ("BA");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, 0);
+			dacl.AddAccess ((AccessControlType)43210, sid, 1, InheritanceFlags.ContainerInherit, PropagationFlags.None);
+		}
+
+		[Test]
+		public void RemoveSpecific ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BA");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, 0);
+
+			RemoveSpecificBegin (sid, dacl, InheritanceFlags.None);
+			dacl.RemoveAccessSpecific (AccessControlType.Allow, sid, 3, InheritanceFlags.None, PropagationFlags.None);
+			Assert.AreEqual (0, dacl.Count);
+		}
+
+		[Test]
+		public void RemoveSpecificUsingDSOverload ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BA");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, true, 0);
+
+			RemoveSpecificBegin (sid, dacl, InheritanceFlags.None);
+			dacl.RemoveAccessSpecific (AccessControlType.Allow, sid, 3, InheritanceFlags.None, PropagationFlags.None,
+			                           ObjectAceFlags.ObjectAceTypePresent, Guid.Empty, Guid.Empty);
+			Assert.AreEqual (1, dacl.Count);
+			dacl.RemoveAccessSpecific (AccessControlType.Allow, sid, 3, InheritanceFlags.None, PropagationFlags.None,
+			                           ObjectAceFlags.None, Guid.Empty, Guid.Empty);
+			Assert.AreEqual (0, dacl.Count);
+		}
+
+		[Test]
+		public void RemoveSpecificIsContainer ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BA");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (true, false, 0);
+
+			RemoveSpecificBegin (sid, dacl, InheritanceFlags.ObjectInherit);
+			dacl.RemoveAccessSpecific (AccessControlType.Allow, sid, 3, InheritanceFlags.ObjectInherit, PropagationFlags.None);
+			Assert.AreEqual (0, dacl.Count);
+		}
+
+		[Test]
+		public void RemoveSpecificIgnoresPropagationFlagsWhenMatchingInheritanceFlagsNone()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BA");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, 0);
+
+			RemoveSpecificBegin (sid, dacl, InheritanceFlags.None);
+			dacl.RemoveAccessSpecific (AccessControlType.Allow, sid, 3,
+			                           InheritanceFlags.None, PropagationFlags.InheritOnly);
+			Assert.AreEqual (0, dacl.Count);
+		}
+
+		void RemoveSpecificBegin (SecurityIdentifier sid, DiscretionaryAcl dacl, InheritanceFlags inheritanceFlags)
+		{
+			SecurityIdentifier otherSid = new SecurityIdentifier ("BU");
+
+			dacl.AddAccess (AccessControlType.Allow, sid, 3, inheritanceFlags, PropagationFlags.None);
+			Assert.AreEqual (1, dacl.Count);
+			dacl.RemoveAccessSpecific (AccessControlType.Deny, sid, 1, inheritanceFlags, PropagationFlags.None);
+			Assert.AreEqual (1, dacl.Count);
+			dacl.RemoveAccessSpecific (AccessControlType.Allow, otherSid, 1, inheritanceFlags, PropagationFlags.None);
+			Assert.AreEqual (1, dacl.Count);
+			dacl.RemoveAccessSpecific (AccessControlType.Allow, sid, 1, inheritanceFlags, PropagationFlags.None);
+			Assert.AreEqual (1, dacl.Count);
+			Assert.AreEqual (3, ((CommonAce)dacl [0]).AccessMask);
+			dacl.RemoveAccessSpecific (AccessControlType.Allow, sid, 3,
+			                           inheritanceFlags ^ InheritanceFlags.ContainerInherit,
+			                           PropagationFlags.None);
+			Assert.AreEqual (1, dacl.Count);
+		}
+
+		[Test]
+		public void PropagationFlagsDoNotRequireInheritanceFlagsForRemoveSpecific ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier ("BU");
+			DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, 0);
+			dacl.RemoveAccessSpecific (AccessControlType.Allow, sid, 3,
+			                           InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly);
+		}
+
+		[Test]
+		public void SetAccess ()
+		{
+			SecurityIdentifier adminSid = new SecurityIdentifier ("BA"); // S-1-5-32-544
+			SecurityIdentifier userSid = new SecurityIdentifier ("BU"); // S-1-5-32-545
+
+			DiscretionaryAcl dacl = new DiscretionaryAcl (true, false, 0);
+			dacl.SetAccess (AccessControlType.Allow, adminSid, 1, InheritanceFlags.ObjectInherit, PropagationFlags.None);
+			dacl.SetAccess (AccessControlType.Allow, userSid, 2, InheritanceFlags.None, PropagationFlags.None);
+			Assert.AreEqual (2, dacl.Count);
+
+			CommonAce ace = (CommonAce)dacl [0];
+			Assert.AreEqual (adminSid, ace.SecurityIdentifier);
+			Assert.AreEqual (1, ace.AccessMask);
+
+			dacl.SetAccess (AccessControlType.Allow, adminSid, 4, InheritanceFlags.ObjectInherit, PropagationFlags.None);
+			Assert.AreNotEqual (4, ace.AccessMask); // remove and add, not modify, despite AccessMask having a setter
+			ace = (CommonAce)dacl [0];
+			Assert.AreEqual (4, ace.AccessMask);
+
+			dacl.SetAccess (AccessControlType.Deny, adminSid, 4, InheritanceFlags.ObjectInherit, PropagationFlags.None);
+			Assert.AreEqual (3, dacl.Count);
+			ace = (CommonAce)dacl [0];
+			Assert.AreEqual (AceQualifier.AccessDenied, ace.AceQualifier);
+			ace = (CommonAce)dacl [1];
+			Assert.AreEqual (AceQualifier.AccessAllowed, ace.AceQualifier);
+		}
+	}
+}
+

+ 7 - 0
mcs/class/corlib/Test/System.Security.AccessControl/RawAclTest.cs

@@ -5,6 +5,7 @@
 //	Kenneth Bell
 //
 
+using System;
 using System.Security.AccessControl;
 using System.Security.Principal;
 using NUnit.Framework;
@@ -37,5 +38,11 @@ namespace MonoTests.System.Security.AccessControl {
 				0x00, 0x00 };
 			Assert.AreEqual (sdBinary, buffer);
 		}
+		
+		[Test, ExpectedException (typeof (ArgumentOutOfRangeException))]
+		public void NonNegativeCapacity ()
+		{
+			new RawAcl (GenericAcl.AclRevision, -1);
+		}
 	}
 }

+ 14 - 0
mcs/class/corlib/Test/System.Security.Principal/SecurityIdentifierTest.cs

@@ -325,5 +325,19 @@ namespace MonoTests.System.Security.Principal {
 			Assert.AreSame (sids [2], sortedSids [4]);
 			Assert.AreSame (sids [3], sortedSids [5]);
 		}
+		
+		[Test, ExpectedExceptionAttribute (typeof (ArgumentNullException))]
+		public void CompareToNull ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
+			sid.CompareTo ((SecurityIdentifier)null);
+		}
+
+		public void EqualsNull ()
+		{
+			SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
+			Assert.IsFalse (sid.Equals ((object)null));
+			Assert.IsFalse (sid.Equals ((SecurityIdentifier)null));
+		}
 	}
 }

+ 1 - 0
mcs/class/corlib/corlib_test.dll.sources

@@ -207,6 +207,7 @@ System.Security/CodeAccessPermissionTest.cs
 System.Security.AccessControl/AuthorizationRuleTest.cs
 System.Security.AccessControl/CommonAceTest.cs
 System.Security.AccessControl/CommonAclTest.cs
+System.Security.AccessControl/DiscretionaryAclTest.cs
 System.Security.AccessControl/MutexAccessRuleTest.cs
 System.Security.AccessControl/ObjectAceTest.cs
 System.Security.AccessControl/ObjectSecurity_TTest.cs