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.Collections;
6 using System.Linq;
7 using System.Runtime.InteropServices;
8 using System.Security.Principal;
9 using Xunit;
10 
11 namespace System.Security.AccessControl.Tests
12 {
13     [Flags]
14     public enum FlagsForAce : byte
15     {
16         None = 0x00,
17         OI = 0x01,
18         CI = 0x02,
19         NP = 0x04,
20         IO = 0x08,
21         IH = 0x10,
22         SA = 0x40,
23         FA = 0x80,
24 
25         InheritanceFlags = OI | CI | NP | IO,
26         AuditFlags = SA | FA,
27     }
28 
29     public class Utils
30     {
IsAceEqual(GenericAce ace1, GenericAce ace2)31         public static bool IsAceEqual(GenericAce ace1, GenericAce ace2)
32         {
33             bool result = true;
34             byte[] ace1BinaryForm;
35             byte[] ace2BinaryForm;
36 
37 
38             if (null != ace1 && null != ace2)
39             {
40                 //check the BinaryLength
41                 if (ace1.BinaryLength != ace2.BinaryLength)
42                 {
43                     result = false;
44                 }
45                 else
46                 {
47                     ace1BinaryForm = new byte[ace1.BinaryLength];
48                     ace2BinaryForm = new byte[ace2.BinaryLength];
49                     ace1.GetBinaryForm(ace1BinaryForm, 0);
50                     ace2.GetBinaryForm(ace2BinaryForm, 0);
51                     if (!IsBinaryFormEqual(ace1BinaryForm, ace2BinaryForm))
52                     {
53                         result = false;
54                     }
55                 }
56             }
57             else if (null == ace1 && null == ace2)
58             {
59                 Console.WriteLine("Both aces are null");
60             }
61             else
62                 result = false;
63             return result;
64         }
65 
IsBinaryFormEqual(byte[] binaryForm1, int offset, byte[] binaryForm2)66         public static bool IsBinaryFormEqual(byte[] binaryForm1, int offset, byte[] binaryForm2)
67         {
68             bool result = true;
69             if (null == binaryForm1 && null == binaryForm2)
70                 result = true;
71             else if (null != binaryForm1 && null != binaryForm2)
72             {
73                 if (binaryForm1.Length - offset != binaryForm2.Length)
74                 {
75                     result = false;
76                 }
77                 else
78                 {
79                     for (int i = 0; i < binaryForm2.Length; i++)
80                     {
81                         if (binaryForm1[offset + i] != binaryForm2[i])
82                         {
83                             result = false;
84                             break;
85                         }
86                     }
87                 }
88             }
89             else
90                 result = false;
91             return result;
92         }
93 
IsBinaryFormEqual(byte[] binaryForm1, byte[] binaryForm2)94         public static bool IsBinaryFormEqual(byte[] binaryForm1, byte[] binaryForm2)
95         {
96             return IsBinaryFormEqual(binaryForm1, 0, binaryForm2);
97         }
98 
CreateRawAclFromString(string rawAclString)99         public static RawAcl CreateRawAclFromString(string rawAclString)
100         {
101             RawAcl rawAcl = null;
102             byte revision = 0;
103             int capacity = 1;
104             CommonAce cAce = null;
105             AceFlags aceFlags = AceFlags.None;
106             AceQualifier aceQualifier = AceQualifier.AccessAllowed;
107             int accessMask = 1;
108             SecurityIdentifier sid = null;
109             bool isCallback = false;
110             int opaqueSize = 0;
111             byte[] opaque = null;
112 
113 
114             string[] parts = null;
115             string[] subparts = null;
116             char[] delimiter1 = new char[] { '#' };
117             char[] delimiter2 = new char[] { ':' };
118 
119             if (rawAclString != null)
120             {
121                 rawAcl = new RawAcl(revision, capacity);
122 
123                 parts = rawAclString.Split(delimiter1);
124                 for (int i = 0; i < parts.Length; i++)
125                 {
126                     subparts = parts[i].Split(delimiter2);
127                     if (subparts.Length != 6)
128                     {
129                         return null;
130                     }
131 
132                     aceFlags = (AceFlags)byte.Parse(subparts[0]);
133                     aceQualifier = (AceQualifier)int.Parse(subparts[1]);
134                     accessMask = int.Parse(subparts[2]);
135                     sid = new SecurityIdentifier(TranslateStringConstFormatSidToStandardFormatSid(subparts[3]));
136                     isCallback = bool.Parse(subparts[4]);
137                     if (!isCallback)
138                         opaque = null;
139                     else
140                     {
141                         opaqueSize = int.Parse(subparts[5]);
142                         opaque = new byte[opaqueSize];
143                     }
144                     cAce = new CommonAce(aceFlags, aceQualifier, accessMask, sid, isCallback, opaque);
145                     rawAcl.InsertAce(rawAcl.Count, cAce);
146                 }
147             }
148             return rawAcl;
149         }
150 
TranslateStringConstFormatSidToStandardFormatSid(string sidStringConst)151         public static string TranslateStringConstFormatSidToStandardFormatSid(string sidStringConst)
152         {
153             string stFormatSid = null;
154             if (sidStringConst == "BA")
155                 stFormatSid = "S-1-5-32-544";
156             else if (sidStringConst == "BO")
157                 stFormatSid = "S-1-5-32-551";
158             else if (sidStringConst == "BG")
159                 stFormatSid = "S-1-5-32-546";
160 
161             else if (sidStringConst == "AN")
162                 stFormatSid = "S-1-5-7";
163 
164             else if (sidStringConst == "NO")
165                 stFormatSid = "S-1-5-32-556";
166 
167             else if (sidStringConst == "SO")
168                 stFormatSid = "S-1-5-32-549";
169 
170             else if (sidStringConst == "RD")
171                 stFormatSid = "S-1-5-32-555";
172 
173             else if (sidStringConst == "SY")
174                 stFormatSid = "S-1-5-18";
175 
176             else
177                 stFormatSid = sidStringConst;
178             return stFormatSid;
179         }
180 
PrintBinaryForm(byte[] binaryForm)181         public static void PrintBinaryForm(byte[] binaryForm)
182         {
183             Console.WriteLine();
184 
185             if (binaryForm != null)
186             {
187                 Console.WriteLine("BinaryForm:");
188                 for (int i = 0; i < binaryForm.Length; i++)
189                 {
190                     Console.WriteLine("{0}", binaryForm[i]);
191                 }
192                 Console.WriteLine();
193             }
194             else
195                 Console.WriteLine("BinaryForm: null");
196         }
197 
ComputeBinaryLength(CommonSecurityDescriptor commonSecurityDescriptor, bool needCountDacl)198         public static int ComputeBinaryLength(CommonSecurityDescriptor commonSecurityDescriptor, bool needCountDacl)
199         {
200             int verifierBinaryLength = 0;
201             if (commonSecurityDescriptor != null)
202             {
203                 verifierBinaryLength = 20; //initialize the binary length to header length
204                 if (commonSecurityDescriptor.Owner != null)
205                     verifierBinaryLength += commonSecurityDescriptor.Owner.BinaryLength;
206                 if (commonSecurityDescriptor.Group != null)
207                     verifierBinaryLength += commonSecurityDescriptor.Group.BinaryLength;
208                 if ((commonSecurityDescriptor.ControlFlags & ControlFlags.SystemAclPresent) != 0 && commonSecurityDescriptor.SystemAcl != null)
209                     verifierBinaryLength += commonSecurityDescriptor.SystemAcl.BinaryLength;
210                 if ((commonSecurityDescriptor.ControlFlags & ControlFlags.DiscretionaryAclPresent) != 0 && commonSecurityDescriptor.DiscretionaryAcl != null && needCountDacl)
211                     verifierBinaryLength += commonSecurityDescriptor.DiscretionaryAcl.BinaryLength;
212             }
213 
214             return verifierBinaryLength;
215         }
216         //verify the dacl is crafted with one Allow Everyone Everything ACE
217 
VerifyDaclWithCraftedAce(bool isContainer, bool isDS, DiscretionaryAcl dacl)218         public static bool VerifyDaclWithCraftedAce(bool isContainer, bool isDS, DiscretionaryAcl dacl)
219         {
220             byte[] craftedBForm;
221             byte[] binaryForm;
222 
223             DiscretionaryAcl craftedDacl = new DiscretionaryAcl(isContainer, isDS, 1);
224             craftedDacl.AddAccess(AccessControlType.Allow,
225                 new SecurityIdentifier("S-1-1-0"),
226                 -1,
227                 isContainer ? InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit : InheritanceFlags.None,
228                 PropagationFlags.None);
229             craftedBForm = new byte[craftedDacl.BinaryLength];
230             binaryForm = new byte[dacl.BinaryLength];
231             Assert.False(craftedBForm == null || binaryForm == null);
232             craftedDacl.GetBinaryForm(craftedBForm, 0);
233             dacl.GetBinaryForm(binaryForm, 0);
234 
235             return Utils.IsBinaryFormEqual(craftedBForm, binaryForm);
236 
237         }
238 
CopyRawACL(RawAcl rawAcl)239         public static RawAcl CopyRawACL(RawAcl rawAcl)
240         {
241             byte[] binaryForm = new byte[rawAcl.BinaryLength];
242             rawAcl.GetBinaryForm(binaryForm, 0);
243             return new RawAcl(binaryForm, 0);
244         }
245 
AclPartialEqual(GenericAcl acl1, GenericAcl acl2, int acl1StartAceIndex, int acl1EndAceIndex, int acl2StartAceIndex, int acl2EndAceIndex)246         public static bool AclPartialEqual(GenericAcl acl1, GenericAcl acl2, int acl1StartAceIndex, int acl1EndAceIndex, int acl2StartAceIndex, int acl2EndAceIndex)
247         {
248             int index1 = 0;
249             int index2 = 0;
250             bool result = true;
251             if (null != acl1 && null != acl2)
252             {
253                 if (acl1StartAceIndex < 0 || acl1EndAceIndex < 0 || acl1StartAceIndex > acl1.Count - 1 || acl1EndAceIndex > acl1.Count - 1 ||
254                     acl2StartAceIndex < 0 || acl2EndAceIndex < 0 || acl2StartAceIndex > acl2.Count - 1 || acl2EndAceIndex > acl2.Count - 1)
255                 {
256                     //the caller has garenteeed the index calculation is correct so if any above condition hold,
257                     //that means the range of the index is invalid
258                     return true;
259                 }
260                 if (acl1EndAceIndex - acl1StartAceIndex != acl2EndAceIndex - acl2StartAceIndex)
261                 {
262                     result = false;
263                 }
264                 else
265                 {
266                     for (index1 = acl1StartAceIndex, index2 = acl2StartAceIndex; index1 <= acl1EndAceIndex; index1++, index2++)
267                     {
268                         if (!Utils.IsAceEqual(acl1[index1], acl2[index2]))
269                         {
270                             result = false;
271                             break;
272                         }
273                     }
274                 }
275             }
276             else if (null == acl1 && null == acl2)
277             {
278             }
279             else
280                 result = false;
281 
282             return result;
283         }
284 
TestGetEnumerator(IEnumerator enumerator, RawAcl rAcl, bool isExplicit)285         public static bool TestGetEnumerator(IEnumerator enumerator, RawAcl rAcl, bool isExplicit)
286         {
287             bool result = false;//assume failure
288             GenericAce gAce = null;
289             if (!(isExplicit ? enumerator.MoveNext() : ((AceEnumerator)enumerator).MoveNext()))
290             {//enumerator is created from empty RawAcl
291                 if (0 != rAcl.Count)
292                     return false;
293                 else
294                     return true;
295             }
296             else if (0 == rAcl.Count)
297             {//rawAcl is empty but enumerator is still enumerable
298                 return false;
299             }
300             else//non-empty rAcl, non-empty enumerator
301             {
302                 //check all aces enumerated are in the RawAcl
303                 if (isExplicit)
304                 {
305                     enumerator.Reset();
306                 }
307                 else
308                 {
309                     ((AceEnumerator)enumerator).Reset();
310                 }
311                 while (isExplicit ? enumerator.MoveNext() : ((AceEnumerator)enumerator).MoveNext())
312                 {
313                     gAce = (GenericAce)(isExplicit ? enumerator.Current : ((AceEnumerator)enumerator).Current);
314                     //check this gAce exists in the RawAcl
315                     for (int i = 0; i < rAcl.Count; i++)
316                     {
317                         if (GenericAce.ReferenceEquals(gAce, rAcl[i]))
318                         {//found
319                             result = true;
320                             break;
321                         }
322                     }
323                     if (!result)
324                     {//not exists in the RawAcl, failed
325                         return false;
326                     }
327                     //enumerate to next one
328                 }
329                 //check all aces of rAcl are enumerable by the enumerator
330                 result = false; //assume failure
331                 for (int i = 0; i < rAcl.Count; i++)
332                 {
333                     gAce = rAcl[i];
334                     //check this gAce is enumerable
335                     if (isExplicit)
336                     {
337                         enumerator.Reset();
338                     }
339                     else
340                     {
341                         ((AceEnumerator)enumerator).Reset();
342                     }
343 
344                     while (isExplicit ? enumerator.MoveNext() : ((AceEnumerator)enumerator).MoveNext())
345                     {
346                         if (GenericAce.ReferenceEquals((GenericAce)(isExplicit ? enumerator.Current : ((AceEnumerator)enumerator).Current), gAce))
347                         {
348                             result = true;
349                             break;
350                         }
351                     }
352                     if (!result)
353                     {//not enumerable
354                         return false;
355                     }
356                     //check next ace in the rAcl
357                 }
358                 //now all passed
359                 return true;
360             }
361         }
362 
363         public sealed class Win32AclLayer
364         {
365             internal const int ERROR_NOT_ENOUGH_MEMORY = 0x8;
366             internal const int VER_PLATFORM_WIN32_NT = 2;
367             [DllImport("Advapi32.dll", EntryPoint = "InitializeAcl", CharSet = CharSet.Unicode, SetLastError = true)]
InitializeAclNative( byte[] acl, uint aclLength, uint aclRevision)368             internal static extern int InitializeAclNative(
369             byte[] acl,
370             uint aclLength,
371             uint aclRevision);
372             [DllImport("Advapi32.dll", EntryPoint = "AddAccessAllowedAceEx", CharSet = CharSet.Unicode, SetLastError = true)]
AddAccessAllowedAceExNative( byte[] acl, uint aclRevision, uint aceFlags, uint accessMask, byte[] sid)373             internal static extern int AddAccessAllowedAceExNative(
374             byte[] acl,
375             uint aclRevision,
376             uint aceFlags,
377             uint accessMask,
378             byte[] sid);
379             [DllImport("Advapi32.dll", EntryPoint = "AddAccessDeniedAceEx", CharSet = CharSet.Unicode, SetLastError = true)]
AddAccessDeniedAceExNative( byte[] acl, uint aclRevision, uint aceFlags, uint accessMask, byte[] sid)380             internal static extern int AddAccessDeniedAceExNative(
381             byte[] acl,
382             uint aclRevision,
383             uint aceFlags,
384             uint accessMask,
385             byte[] sid);
386             [DllImport("Advapi32.dll", EntryPoint = "AddAuditAccessAceEx", CharSet = CharSet.Unicode, SetLastError = true)]
AddAuditAccessAceExNative( byte[] acl, uint aclRevision, uint aceFlags, uint accessMask, byte[] sid, uint bAuditSccess, uint bAuditFailure)387             internal static extern int AddAuditAccessAceExNative(
388             byte[] acl,
389             uint aclRevision,
390             uint aceFlags,
391             uint accessMask,
392             byte[] sid,
393             uint bAuditSccess,
394             uint bAuditFailure);
395         }
396     }
397 }
398