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