1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.Security.Principal; 8 using Xunit; 9 10 namespace System.Security.AccessControl.Tests 11 { 12 public partial class SystemAcl_RemoveAudit 13 { SystemAcl_RemoveAudit_TestData()14 public static IEnumerable<object[]> SystemAcl_RemoveAudit_TestData() 15 { 16 yield return new object[] { true, false, 1, "BA", 1, 0, 0, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#79:2:1:BA:false:0", true }; 17 yield return new object[] { true, false, 1, "BA", 1, 0, 1, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#79:2:1:BA:false:0", true }; 18 yield return new object[] { true, false, 1, "BA", 1, 0, 2, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#79:2:1:BA:false:0", true }; 19 yield return new object[] { true, false, 1, "BA", 1, 0, 3, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#79:2:1:BA:false:0", true }; 20 yield return new object[] { true, false, 1, "BA", 1, 1, 0, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#77:2:1:BA:false:0", true }; 21 yield return new object[] { true, false, 1, "BA", 1, 1, 1, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#77:2:1:BA:false:0", true }; 22 yield return new object[] { true, false, 1, "BA", 1, 1, 2, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#69:2:1:BA:false:0", true }; 23 yield return new object[] { true, false, 1, "BA", 1, 1, 3, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#69:2:1:BA:false:0", true }; 24 yield return new object[] { true, false, 1, "BA", 1, 2, 0, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#78:2:1:BA:false:0", true }; 25 yield return new object[] { true, false, 1, "BA", 1, 2, 1, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#78:2:1:BA:false:0", true }; 26 yield return new object[] { true, false, 1, "BA", 1, 2, 2, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#70:2:1:BA:false:0", true }; 27 yield return new object[] { true, false, 1, "BA", 1, 2, 3, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#70:2:1:BA:false:0", true }; 28 yield return new object[] { true, false, 1, "BA", 1, 3, 0, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0", true }; 29 yield return new object[] { true, false, 1, "BA", 1, 3, 1, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0", true }; 30 yield return new object[] { true, false, 1, "BA", 1, 3, 2, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#64:2:1:BA:false:0", true }; 31 yield return new object[] { true, false, 1, "BA", 1, 3, 3, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#64:2:1:BA:false:0", true }; 32 yield return new object[] { true, false, 1, "BO", 1, 3, 3, "199:2:3:BA:false:0#199:2:3:BG:false:0#199:2:3:BO:false:0", "199:2:3:BA:false:0#199:2:3:BG:false:0#199:2:2:BO:false:0#135:2:1:BO:false:0#64:2:1:BO:false:0", true }; 33 yield return new object[] { true, false, 1, "BG", 1, 3, 3, "199:2:3:BA:false:0#199:2:3:BG:false:0#199:2:3:BO:false:0", "199:2:3:BA:false:0#199:2:2:BG:false:0#135:2:1:BG:false:0#64:2:1:BG:false:0#199:2:3:BO:false:0", true }; 34 yield return new object[] { true, false, 1, "BA", 1, 3, 3, "199:2:3:BA:false:0#199:2:3:BA:false:0#199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#64:2:1:BA:false:0#199:2:2:BA:false:0#135:2:1:BA:false:0#64:2:1:BA:false:0", true }; 35 yield return new object[] { true, false, 1, "BA", 5, 3, 3, "199:2:3:BA:false:0", "199:2:2:BA:false:0#135:2:1:BA:false:0#64:2:1:BA:false:0", true }; 36 yield return new object[] { true, false, 1, "BO", 1, 2, 3, "199:2:3:BA:false:0", "199:2:3:BA:false:0", true }; 37 yield return new object[] { true, false, 1, "BA", 1, 2, 3, "215:2:3:BA:false:0", "215:2:3:BA:false:0", true }; 38 yield return new object[] { true, false, 1, "BA", 4, 2, 3, "199:2:3:BA:false:0", "199:2:3:BA:false:0", true }; 39 yield return new object[] { true, false, 1, "BA", 1, 2, 3, "135:2:3:BA:false:0", "135:2:3:BA:false:0", true }; 40 yield return new object[] { true, false, 3, "BA", 1, 0, 0, "199:2:3:BA:false:0", "199:2:2:BA:false:0#207:2:1:BA:false:0", true }; 41 yield return new object[] { true, false, 1, "BA", 3, 0, 0, "199:2:3:BA:false:0", "135:2:3:BA:false:0#79:2:3:BA:false:0", true }; 42 yield return new object[] { true, false, 1, "BA", 1, 1, 3, "202:2:3:BA:false:0", "202:2:3:BA:false:0", false }; 43 } 44 45 [Theory] 46 [MemberData(nameof(SystemAcl_RemoveAudit_TestData))] BasicValidationTestCases(bool isContainer, bool isDS, int auditFlags, string sid, int accessMask, int inheritanceFlags, int propagationFlags, string initialRawAclStr, string verifierRawAclStr, bool removePossible)47 public static void BasicValidationTestCases(bool isContainer, bool isDS, int auditFlags, string sid, int accessMask, int inheritanceFlags, int propagationFlags, string initialRawAclStr, string verifierRawAclStr, bool removePossible) 48 { 49 RawAcl rawAcl = null; 50 SystemAcl systemAcl = null; 51 52 //create a systemAcl 53 rawAcl = Utils.CreateRawAclFromString(initialRawAclStr); 54 systemAcl = new SystemAcl(isContainer, isDS, rawAcl); 55 rawAcl = Utils.CreateRawAclFromString(verifierRawAclStr); 56 57 Assert.True(TestRemoveAudit(systemAcl, rawAcl, (AuditFlags)auditFlags, new SecurityIdentifier(Utils.TranslateStringConstFormatSidToStandardFormatSid(sid)), accessMask, (InheritanceFlags)inheritanceFlags, (PropagationFlags)propagationFlags, removePossible)); 58 } 59 TestRemoveAudit(SystemAcl systemAcl, RawAcl rawAcl, AuditFlags auditFlag, SecurityIdentifier sid, int accessMask, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, bool removePossible)60 private static bool TestRemoveAudit(SystemAcl systemAcl, RawAcl rawAcl, AuditFlags auditFlag, SecurityIdentifier sid, int accessMask, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, bool removePossible) 61 { 62 bool result = true; 63 bool isRemoved = false; 64 byte[] sAclBinaryForm = null; 65 byte[] rAclBinaryForm = null; 66 isRemoved = systemAcl.RemoveAudit(auditFlag, sid, accessMask, inheritanceFlags, propagationFlags); 67 if ((isRemoved == removePossible) && 68 (systemAcl.Count == rawAcl.Count) && 69 (systemAcl.BinaryLength == rawAcl.BinaryLength)) 70 { 71 sAclBinaryForm = new byte[systemAcl.BinaryLength]; 72 rAclBinaryForm = new byte[rawAcl.BinaryLength]; 73 systemAcl.GetBinaryForm(sAclBinaryForm, 0); 74 rawAcl.GetBinaryForm(rAclBinaryForm, 0); 75 76 if (!Utils.IsBinaryFormEqual(sAclBinaryForm, rAclBinaryForm)) 77 result = false; 78 //redundant index check 79 for (int i = 0; i < systemAcl.Count; i++) 80 { 81 if (!Utils.IsAceEqual(systemAcl[i], rawAcl[i])) 82 { 83 result = false; 84 break; 85 } 86 } 87 } 88 else 89 result = false; 90 return result; 91 } 92 93 [Fact] AdditionalTestCases()94 public static void AdditionalTestCases() 95 { 96 RawAcl rawAcl = null; 97 SystemAcl systemAcl = null; 98 bool isContainer = false; 99 bool isDS = false; 100 101 int auditFlags = 0; 102 string sid = null; 103 int accessMask = 1; 104 int inheritanceFlags = 0; 105 int propagationFlags = 0; 106 GenericAce gAce = null; 107 bool removePossible = false; 108 byte[] opaque = null; 109 110 //Case 1, null sid 111 Assert.Throws<ArgumentNullException>(() => 112 { 113 isContainer = false; 114 isDS = false; 115 rawAcl = new RawAcl(0, 1); 116 systemAcl = new SystemAcl(isContainer, isDS, rawAcl); 117 systemAcl.RemoveAudit(AuditFlags.Success, null, 1, InheritanceFlags.None, PropagationFlags.None); 118 }); 119 120 //Case 2, SystemAudit Ace but non AuditFlags 121 AssertExtensions.Throws<ArgumentException>("auditFlags", () => 122 { 123 isContainer = false; 124 isDS = false; 125 rawAcl = new RawAcl(0, 1); 126 systemAcl = new SystemAcl(isContainer, isDS, rawAcl); 127 systemAcl.RemoveAudit(AuditFlags.None, 128 new SecurityIdentifier(Utils.TranslateStringConstFormatSidToStandardFormatSid("BG")), 1, InheritanceFlags.None, PropagationFlags.None); 129 130 }); 131 132 //Case 3, 0 accessMask 133 AssertExtensions.Throws<ArgumentException>("accessMask", () => 134 { 135 isContainer = false; 136 isDS = false; 137 rawAcl = new RawAcl(0, 1); 138 systemAcl = new SystemAcl(isContainer, isDS, rawAcl); 139 systemAcl.RemoveAudit(AuditFlags.Success, 140 new SecurityIdentifier(Utils.TranslateStringConstFormatSidToStandardFormatSid("BG")), 0, InheritanceFlags.None, PropagationFlags.None); 141 142 }); 143 144 //Case 4, remove one audit ACE from the SystemAcl with no ACE 145 isContainer = true; 146 isDS = false; 147 auditFlags = 1; 148 sid = "BA"; 149 accessMask = 1; 150 inheritanceFlags = 3; 151 propagationFlags = 3; 152 removePossible = true; 153 rawAcl = new RawAcl(0, 1); 154 systemAcl = new SystemAcl(isContainer, isDS, rawAcl); 155 Assert.True(TestRemoveAudit(systemAcl, rawAcl, (AuditFlags)auditFlags, 156 new SecurityIdentifier(Utils.TranslateStringConstFormatSidToStandardFormatSid(sid)), accessMask, (InheritanceFlags)inheritanceFlags, (PropagationFlags)propagationFlags, removePossible)); 157 158 //Case 5, remove the last one ACE from the SystemAcl 159 isContainer = true; 160 isDS = false; 161 auditFlags = 1; 162 sid = "BA"; 163 accessMask = 1; 164 inheritanceFlags = 3; 165 propagationFlags = 3; 166 removePossible = true; 167 rawAcl = new RawAcl(0, 1); 168 //79 = AceFlags.SuccessfulAccess | AceFlags.ObjectInherit |AceFlags.ContainerInherit | AceFlags.NoPropagateInherit | AceFlags.InheritOnly 169 gAce = new CommonAce((AceFlags)79, AceQualifier.SystemAudit, accessMask, 170 new SecurityIdentifier(Utils.TranslateStringConstFormatSidToStandardFormatSid(sid)), false, null); 171 rawAcl.InsertAce(rawAcl.Count, gAce); 172 systemAcl = new SystemAcl(isContainer, isDS, rawAcl); 173 //remove the ace to create the validation rawAcl 174 rawAcl.RemoveAce(rawAcl.Count - 1); 175 Assert.True(TestRemoveAudit(systemAcl, rawAcl, (AuditFlags)auditFlags, 176 new SecurityIdentifier(Utils.TranslateStringConstFormatSidToStandardFormatSid(sid)), accessMask, (InheritanceFlags)inheritanceFlags, (PropagationFlags)propagationFlags, removePossible)); 177 178 //Case 6, all the ACEs in the Sacl are non-qualified ACE, no remove 179 Assert.Throws<InvalidOperationException>(() => 180 { 181 isContainer = true; 182 isDS = false; 183 inheritanceFlags = 1;//InheritanceFlags.ContainerInherit 184 propagationFlags = 2; //PropagationFlags.InheritOnly 185 186 auditFlags = 3; 187 sid = "BA"; 188 accessMask = 1; 189 rawAcl = new RawAcl(0, 1); 190 opaque = new byte[4]; 191 gAce = new CustomAce(AceType.MaxDefinedAceType + 1, AceFlags.InheritanceFlags | AceFlags.AuditFlags, opaque); ; 192 rawAcl.InsertAce(0, gAce); 193 systemAcl = new SystemAcl(isContainer, isDS, rawAcl); 194 //After Mark changes design to make ACL with any CustomAce, CompoundAce uncanonical and 195 //forbid the modification on uncanonical ACL, this case will throw InvalidOperationException 196 TestRemoveAudit(systemAcl, rawAcl, (AuditFlags)auditFlags, 197 new SecurityIdentifier(Utils.TranslateStringConstFormatSidToStandardFormatSid(sid)), accessMask, (InheritanceFlags)inheritanceFlags, (PropagationFlags)propagationFlags, true); 198 }); 199 //Case 7, remove split cause overflow 200 // Test case no longer relevant in CoreCLR 201 // Non-canonical ACLs cannot be modified 202 } 203 } 204 } 205