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