/// <summary> /// Add the specific ACE(s) to the provided ACL. /// DACL would be reordered after being added, ACCESS_DENIED_ACE before ACCESS_ALLOWED_ACE. /// </summary> /// <param name="isDACL">Whether it is DACL or SACL</param> /// <param name="acl">The ACL to be added to.</param> /// <param name="aces">The ACE(s) to be added.</param> public static void AddAceToAcl(ref _ACL acl, bool isDACL, params object[] aces) { if (aces == null || aces.Length == 0) { return; } acl.AceCount += (ushort)aces.Length; object[] newAces = new object[acl.AceCount]; if (isDACL) { int i = 0; int j = acl.AceCount - 1; foreach (object tmp in acl.Aces) { if (tmp is _ACCESS_ALLOWED_ACE) { newAces[j--] = tmp; } else if (tmp is _ACCESS_DENIED_ACE) { newAces[i++] = tmp; } else { throw new ArgumentException("Unsupport type of ACE"); } } foreach (object tmp in aces) { if (tmp is _ACCESS_ALLOWED_ACE) { newAces[j--] = tmp; } else if (tmp is _ACCESS_DENIED_ACE) { newAces[i++] = tmp; } else { throw new ArgumentException("Unsupport type of ACE"); } } Debug.Assert(i - j == 1, "New ACE array should be filled."); } else // SACL does not need to be reordered { acl.Aces.CopyTo(newAces, 0); aces.CopyTo(newAces, acl.Aces.Length); } acl.Aces = newAces; acl.AclSize = CalculateAclSize(acl); }
/// <summary> /// PreProcessACLfromCreator. MS-DTYP section 2.5.4.8 /// </summary> /// <param name="acl"> /// ACL to preprocess. /// </param> /// <returns> /// Processed ACL. /// </returns> public static _ACL PreProcessACLfromCreator(_ACL acl) { //Initialize NewACL to Empty ACL //FOR each ACE in ACL DO //IF ACE.Flags does not contain INHERITED_ACE THEN //Append ACE to NewACL //ENDIF //END FOR //RETURN NewACL _ACL newAcl = new _ACL(); newAcl.AclRevision = acl.AclRevision; List<object> newAces = new List<object>(); if (acl.Aces != null) { foreach (object ace in acl.Aces) { _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(ace, "Header"); if ((header.AceFlags & ACE_FLAGS.INHERITED_ACE) == ACE_FLAGS.None) { //Append ACE to NewACL newAces.Add(ace); } } } newAcl.Aces = newAces.ToArray(); newAcl.AceCount = (ushort)newAcl.Aces.Length; newAcl.AclSize = DtypUtility.CalculateAclSize(newAcl); return newAcl; }
/// <summary> /// Calculate AclSize of the given ACL, in bytes. /// </summary> /// <param name="acl">The acl to be retrieved.</param> /// <returns>The size of the given acl, in bytes.</returns> internal static ushort CalculateAclSize(_ACL acl) { //The AclSize contains the following parts: //byte AclRevision;(1 byte) //byte Sbz1;(1 byte) //ushort AclSize;(2 bytes) //ushort AceCount;(2 bytes) //ushort Sbz2;(2 bytes) //object[] Aces;(variable length) ushort sizeOfAcl = ACL_HEADER_LENGTH; for (int i = 0; i < acl.AceCount; i++) { _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(acl.Aces[i], "Header"); sizeOfAcl += header.AceSize; } return sizeOfAcl; }
/// <summary> /// Encode the ACL structure into byte array, according to TD specification. /// </summary> /// <param name="acl">The acl to be retrieved.</param> /// <returns>The encoded byte array.</returns> /// <exception cref="ArgumentException"> /// Thrown when The type of ace is invalid. /// </exception> public static byte[] EncodeAcl(_ACL acl) { List<byte> byteArray = new List<byte>(); byteArray.Add(acl.AclRevision); byteArray.Add(acl.Sbz1); byteArray.AddRange(TypeMarshal.ToBytes<ushort>(acl.AclSize)); byteArray.AddRange(TypeMarshal.ToBytes<ushort>(acl.AceCount)); byteArray.AddRange(TypeMarshal.ToBytes<ushort>(acl.Sbz2)); for (int i = 0; i < acl.AceCount; i++) { _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(acl.Aces[i], "Header"); byte[] tmpByteArray = new byte[] { }; switch (header.AceType) { case ACE_TYPE.ACCESS_ALLOWED_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_ACCESS_ALLOWED_ACE>((_ACCESS_ALLOWED_ACE)acl.Aces[i]); break; case ACE_TYPE.ACCESS_DENIED_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_ACCESS_DENIED_ACE>((_ACCESS_DENIED_ACE)acl.Aces[i]); break; case ACE_TYPE.SYSTEM_AUDIT_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_SYSTEM_AUDIT_ACE>((_SYSTEM_AUDIT_ACE)acl.Aces[i]); break; case ACE_TYPE.ACCESS_ALLOWED_OBJECT_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_ACCESS_ALLOWED_OBJECT_ACE>( (_ACCESS_ALLOWED_OBJECT_ACE)acl.Aces[i]); break; case ACE_TYPE.ACCESS_DENIED_OBJECT_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_ACCESS_DENIED_OBJECT_ACE>( (_ACCESS_DENIED_OBJECT_ACE)acl.Aces[i]); break; case ACE_TYPE.SYSTEM_AUDIT_OBJECT_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_SYSTEM_AUDIT_OBJECT_ACE>( (_SYSTEM_AUDIT_OBJECT_ACE)acl.Aces[i]); break; case ACE_TYPE.ACCESS_ALLOWED_CALLBACK_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_ACCESS_ALLOWED_CALLBACK_ACE>( (_ACCESS_ALLOWED_CALLBACK_ACE)acl.Aces[i]); break; case ACE_TYPE.ACCESS_DENIED_CALLBACK_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_ACCESS_DENIED_CALLBACK_ACE>( (_ACCESS_DENIED_CALLBACK_ACE)acl.Aces[i]); break; case ACE_TYPE.ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE>( (_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE)acl.Aces[i]); break; case ACE_TYPE.ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_ACCESS_DENIED_CALLBACK_OBJECT_ACE>( (_ACCESS_DENIED_CALLBACK_OBJECT_ACE)acl.Aces[i]); break; case ACE_TYPE.SYSTEM_AUDIT_CALLBACK_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_SYSTEM_AUDIT_CALLBACK_ACE>( (_SYSTEM_AUDIT_CALLBACK_ACE)acl.Aces[i]); break; case ACE_TYPE.SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE>( (_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE)acl.Aces[i]); break; case ACE_TYPE.SYSTEM_MANDATORY_LABLE_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_SYSTEM_MANDATORY_LABEL_ACE>( (_SYSTEM_MANDATORY_LABEL_ACE)acl.Aces[i]); break; case ACE_TYPE.SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE: tmpByteArray = ((SystemResourceAttributeAce)acl.Aces[i]).BinaryForm; break; case ACE_TYPE.SYSTEM_SCOPED_POLICY_ID_ACE_TYPE: tmpByteArray = TypeMarshal.ToBytes<_SYSTEM_SCOPED_POLICY_ID_ACE>( (_SYSTEM_SCOPED_POLICY_ID_ACE)acl.Aces[i]); break; default: throw new ArgumentException("The type of ace is invalid", "acl"); } byteArray.AddRange(tmpByteArray); } return byteArray.ToArray(); }
/// <summary> /// PostProcessACL. MS-DTYP section 2.5.4.9 /// </summary> /// <param name="acl">ACL on which to substitute SIDs.</param> /// <param name="copyFilter">The filter for post-processing the ACL.</param> /// <param name="owner">Owner to use in substituting the CreatorOwner SID.</param> /// <param name="group">Group to use in substituting the CreatorGroup SID.</param> /// <param name="genericMapping"> /// Mapping of generic permissions to resource manager-specific /// permissions supplied by the caller. /// </param> /// <returns> /// The computed ACL with the SID substitutions performed. /// </returns> public static _ACL PostProcessACL( _ACL acl, CopyFilter copyFilter, _SID owner, _SID group, GenericMapping genericMapping) { #region Pseudocode v20110329 //// Substitute CreatorOwner and CreatorGroup SIDs and do GenericMapping in ACL //Initialize NewACL to Empty ACL //FOR each ACE in ACL DO // // Determine if this ACE passes the filter to be copied to the new ACL // SET CopyThisAce = FALSE // CASE CopyFilter OF // CopyAllAces: // BEGIN // SET CopyThisAce = TRUE // END // CopyInheritedAces: // BEGIN // IF (ACE.AceFlags contains INHERITED_ACE) THEN // SET CopyThisAce = TRUE // ENDIF // END // CopyExplicitAces: // BEGIN // IF (ACE.AceFlags does not contain INHERITED_ACE) THEN // SET CopyThisAce = TRUE // ENDIF // END // ENDCASE // Set NewACE to ACE // IF (CopyThisAce) THEN // CASE ACE.Sid OF // CREATOR_OWNER: // NewACE.Sid = Owner // CREATOR_GROUP: // NewACE.Sid = Group // ENDCASE // IF (ACE.Mask contains GENERIC_READ) THEN // Add GenericMapping.GenericRead to NewACE.Mask // ENDIF // IF (ACE.Mask contains GENERIC_WRITE) THEN // Add GenericMapping.GenericWrite to NewACE.Mask // ENDIF // IF (ACE.Mask contains GENERIC_EXECUTE) THEN // Add GenericMapping.GenericExecute to NewACE.Mask // ENDIF // Append NewACE to NewACL // ENDIF //END FOR //RETURN NewACL //// END PostProcessACL #endregion _ACL newAcl = new _ACL(); newAcl.AclRevision = acl.AclRevision; newAcl.Aces = new object[] { }; List<object> newAces = new List<object>(); if (acl.Aces != null) { foreach (object ace in acl.Aces) { object newAce = ObjectUtility.DeepClone(ace); _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(newAce, "Header"); bool copyThisAce = false; switch (copyFilter) { case CopyFilter.CopyAllAces: copyThisAce = true; break; case CopyFilter.CopyInheritedAces: if ((header.AceFlags & ACE_FLAGS.INHERITED_ACE) == ACE_FLAGS.INHERITED_ACE) { copyThisAce = true; } break; case CopyFilter.CopyExplicitAces: if ((header.AceFlags & ACE_FLAGS.INHERITED_ACE) == ACE_FLAGS.None) { copyThisAce = true; } break; } if (copyThisAce) { #region Substitute CreatorOwner and CreatorGroup SIDs in ACL _SID sid = (_SID)ObjectUtility.GetFieldValue(newAce, "Sid"); if (ObjectUtility.DeepCompare(sid, GetWellKnownSid(WellKnownSid.CREATOR_OWNER, null))) { ObjectUtility.SetFieldValue(newAce, "Sid", owner); header.AceSize = (ushort)(header.AceSize - (sid.SubAuthorityCount - owner.SubAuthorityCount) * sizeof(uint)); ObjectUtility.SetFieldValue(newAce, "Header", header); } else if (ObjectUtility.DeepCompare(sid, GetWellKnownSid(WellKnownSid.CREATOR_GROUP, null))) { ObjectUtility.SetFieldValue(newAce, "Sid", group); header.AceSize = (ushort)(header.AceSize - (sid.SubAuthorityCount - group.SubAuthorityCount) * sizeof(uint)); ObjectUtility.SetFieldValue(newAce, "Header", header); } #endregion #region Do GenericMapping in ACL uint mask = (uint)ObjectUtility.GetFieldValue(newAce, "Mask"); if ((mask & ACCESS_MASK_GENERIC_READ) == ACCESS_MASK_GENERIC_READ) { mask = mask | genericMapping.GenericRead; ObjectUtility.SetFieldValue(newAce, "Mask", mask); } if ((mask & ACCESS_MASK_GENERIC_WRITE) == ACCESS_MASK_GENERIC_WRITE) { mask = mask | genericMapping.GenericWrite; ObjectUtility.SetFieldValue(newAce, "Mask", mask); } if ((mask & ACCESS_MASK_GENERIC_EXECUTE) == ACCESS_MASK_GENERIC_EXECUTE) { mask = mask | genericMapping.GenericExecute; ObjectUtility.SetFieldValue(newAce, "Mask", mask); } #endregion //Append NewACE to NewACL newAces.Add(newAce); } } } newAcl.Aces = newAces.ToArray(); newAcl.AceCount = (ushort)newAcl.Aces.Length; newAcl.AclSize = DtypUtility.CalculateAclSize(newAcl); return newAcl; }
/// <summary> /// Create a _SECURITY_DESCRIPTOR structure in self-relative format. /// </summary> /// <param name="control">An unsigned 16-bit field that specifies control access bit flags.</param> /// <param name="ownerSid">The SID of the owner of the object</param> /// <param name="groupSid">The SID of the group of the object.</param> /// <param name="sacl">The SACL of the object.</param> /// <param name="dacl">The DACL of the object.</param> /// <returns> Output security descriptor for the object.</returns> public static _SECURITY_DESCRIPTOR CreateSecurityDescriptor( SECURITY_DESCRIPTOR_Control control, _SID? ownerSid, _SID? groupSid, _ACL? sacl, _ACL? dacl) { RawAcl sRawAcl = null; RawAcl dRawAcl = null; SecurityIdentifier rawOwnerSid = null; SecurityIdentifier rawGroupSid = null; if (ownerSid != null) { rawOwnerSid = new SecurityIdentifier(TypeMarshal.ToBytes(ownerSid.Value), 0); } if (groupSid != null) { rawGroupSid = new SecurityIdentifier(TypeMarshal.ToBytes(groupSid.Value), 0); } if (sacl != null) { sRawAcl = new RawAcl(DtypUtility.EncodeAcl(sacl.Value), 0); } if (dacl != null) { dRawAcl = new RawAcl(DtypUtility.EncodeAcl(dacl.Value), 0); } RawSecurityDescriptor rawSecurityDescriptor = new RawSecurityDescriptor( (ControlFlags)control, rawOwnerSid, rawGroupSid, sRawAcl, dRawAcl); byte[] rawSecurityDescriptorBytes = new byte[rawSecurityDescriptor.BinaryLength]; rawSecurityDescriptor.GetBinaryForm(rawSecurityDescriptorBytes, 0); return DtypUtility.DecodeSecurityDescriptor(rawSecurityDescriptorBytes); }
/// <summary> /// Decode the specified buffer into the ACL structure. /// </summary> /// <param name="buffer">The byte array to be decoded.</param> /// <returns>The ACL structure.</returns> /// <exception cref="FormatException"> /// Thrown when the format of input parameter is not correct. /// </exception> /// <exception cref="ArgumentException"> /// Thrown when The type of ace is invalid. /// </exception> public static _ACL DecodeAcl(byte[] buffer) { if (buffer == null || buffer.Length < ACL_HEADER_LENGTH) { throw new FormatException("The token body is incomplete."); } _ACL acl = new _ACL(); List<object> aces = new List<object>(); int index = 0; byte[] tokenBody = new byte[] { }; acl.AclRevision = buffer[0]; acl.Sbz1 = buffer[1]; index += sizeof(byte) * 2; tokenBody = ArrayUtility.SubArray(buffer, index, sizeof(ushort)); acl.AclSize = TypeMarshal.ToStruct<ushort>(tokenBody); index += sizeof(ushort); tokenBody = ArrayUtility.SubArray(buffer, index, sizeof(ushort)); acl.AceCount = TypeMarshal.ToStruct<ushort>(tokenBody); index += sizeof(ushort); tokenBody = ArrayUtility.SubArray(buffer, index, sizeof(ushort)); acl.Sbz2 = TypeMarshal.ToStruct<ushort>(tokenBody); index += sizeof(ushort); for (int i = 0; i < acl.AceCount; i++) { tokenBody = ArrayUtility.SubArray(buffer, index, ACE_HEADER_LENGTH); _ACE_HEADER header = TypeMarshal.ToStruct<_ACE_HEADER>(tokenBody); object ace = null; tokenBody = ArrayUtility.SubArray(buffer, index, header.AceSize); switch (header.AceType) { case ACE_TYPE.ACCESS_ALLOWED_ACE_TYPE: ace = TypeMarshal.ToStruct<_ACCESS_ALLOWED_ACE>(tokenBody); break; case ACE_TYPE.ACCESS_DENIED_ACE_TYPE: ace = TypeMarshal.ToStruct<_ACCESS_DENIED_ACE>(tokenBody); break; case ACE_TYPE.SYSTEM_AUDIT_ACE_TYPE: ace = TypeMarshal.ToStruct<_SYSTEM_AUDIT_ACE>(tokenBody); break; case ACE_TYPE.ACCESS_ALLOWED_OBJECT_ACE_TYPE: ace = TypeMarshal.ToStruct<_ACCESS_ALLOWED_OBJECT_ACE>(tokenBody); break; case ACE_TYPE.ACCESS_DENIED_OBJECT_ACE_TYPE: ace = TypeMarshal.ToStruct<_ACCESS_DENIED_OBJECT_ACE>(tokenBody); break; case ACE_TYPE.SYSTEM_AUDIT_OBJECT_ACE_TYPE: ace = TypeMarshal.ToStruct<_SYSTEM_AUDIT_OBJECT_ACE>(tokenBody); break; case ACE_TYPE.ACCESS_ALLOWED_CALLBACK_ACE_TYPE: ace = TypeMarshal.ToStruct<_ACCESS_ALLOWED_CALLBACK_ACE>(tokenBody); break; case ACE_TYPE.ACCESS_DENIED_CALLBACK_ACE_TYPE: ace = TypeMarshal.ToStruct<_ACCESS_DENIED_CALLBACK_ACE>(tokenBody); break; case ACE_TYPE.ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE: ace = TypeMarshal.ToStruct<_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE>(tokenBody); break; case ACE_TYPE.ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE: ace = TypeMarshal.ToStruct<_ACCESS_DENIED_CALLBACK_OBJECT_ACE>(tokenBody); break; case ACE_TYPE.SYSTEM_AUDIT_CALLBACK_ACE_TYPE: ace = TypeMarshal.ToStruct<_SYSTEM_AUDIT_CALLBACK_ACE>(tokenBody); break; case ACE_TYPE.SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE: ace = TypeMarshal.ToStruct<_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE>(tokenBody); break; case ACE_TYPE.SYSTEM_MANDATORY_LABLE_ACE_TYPE: ace = TypeMarshal.ToStruct<_SYSTEM_MANDATORY_LABEL_ACE>(tokenBody); break; case ACE_TYPE.SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE: ace = SystemResourceAttributeAce.FromBytes(tokenBody); break; case ACE_TYPE.SYSTEM_SCOPED_POLICY_ID_ACE_TYPE: ace = TypeMarshal.ToStruct<_SYSTEM_SCOPED_POLICY_ID_ACE>(tokenBody); break; default: throw new ArgumentException("The type of ace is invalid.", "buffer"); } index += header.AceSize; aces.Add(ace); } acl.Aces = aces.ToArray(); return acl; }
/// <summary> /// Create an ACL with provided ACE(s). /// </summary> /// <param name="isDACL">Whether it is DACL or SACL</param> /// <param name="aces">The ACE(s) to be put into the ACL.</param> /// <returns>The constructed ACL structure.</returns> public static _ACL CreateAcl(bool isDACL, params object[] aces) { _ACL acl = new _ACL { AceCount = 0, Aces = new object[0], AclRevision = 0x02, // AclRevision (1 byte) + Sbz1 (1 byte) + AclSize (2 bytes) // + AceCount (2 bytes) + Sbz2 (2 bytes) AclSize = 8, Sbz1 = 0, Sbz2 = 0 }; if (aces != null && aces.Length != 0) { AddAceToAcl(ref acl, isDACL, aces); } return acl; }
/// <summary> /// ContainsInheritableACEs. MS-DTYP section 2.5.4.5 /// </summary> /// <param name="acl">ACL</param> /// <returns>Return TRUE if contains inheritable ACE; otherwise, FALSE.</returns> public static bool ContainsInheritableACEs(_ACL acl) { //FOR each ACE in ACL DO //IF(ACE.Flags contains CONTAINER_INHERIT_ACE) OR //(ACE.Flags contains OBJECT_INHERIT_ACE) //THEN //RETURN TRUE //ENDIF //END FOR //RETURN FALSE if (acl.Aces != null) { foreach (object ace in acl.Aces) { object newAce = ObjectUtility.DeepClone(ace); _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(newAce, "Header"); if ((header.AceFlags & ACE_FLAGS.CONTAINER_INHERIT_ACE) == ACE_FLAGS.CONTAINER_INHERIT_ACE || (header.AceFlags & ACE_FLAGS.OBJECT_INHERIT_ACE) == ACE_FLAGS.OBJECT_INHERIT_ACE) { return true; } } } return false; }
/// <summary> /// ComputeInheritedACLfromParent. MS-DTYP section 2.5.4.6 /// </summary> /// <param name="acl"> /// An ACL that contains the parent's ACEs from which to compute the inherited ACL. /// </param> /// <param name="isContainerObject"> /// TRUE if the object is a container; otherwise, FALSE. /// </param> /// <param name="objectTypes"> /// An array of GUIDs for the object type being created. /// </param> /// <returns> /// The computed ACL that also includes the inherited ACEs. /// </returns> public static _ACL ComputeInheritedACLfromParent( _ACL acl, bool isContainerObject, Guid[] objectTypes) { //Initialize ExplicitACL to Empty ACL //FOR each ACE in ACL DO //IF ACE.Flags contains INHERIT_ONLY_ACE //THEN //CONTINUE //ENDIF //IF(((ACE.Flags contains CONTAINER_INHERIT_ACE) AND //(IsContainerObject = TRUE))OR //((ACE.Flags contains OBJECT_INHERIT_ACE) AND //(IsContainerObject = FALSE))) //THEN // CASE ACE.Type OF // ALLOW: // DENY: // Set NewACE to ACE // Set NewACE.Flags to INHERITED_ACE // Append NewACE to ExplicitACL // OBJECT_ALLOW: // OBJECT_DENY: // IF (ObjectTypes contains ACE.ObjectGUID) THEN // Set NewACE to ACE // Set NewACE.Flags to INHERITED_ACE // Append NewACE to ExplicitACL // ENDIF // ENDCASE //ENDIF //END FOR //Initialize InheritableACL to Empty ACL //IF (IsContainerObject = TRUE) THEN //FOR each ACE in ACL DO //IF ACE.Flags contains NO_PROPAGATE_INHERIT_ACE THEN //CONTINUE //ENDIF //IF((ACE.Flags contains CONTAINER_INHERIT_ACE) OR //(ACE.Flags contains OBJECT_INHERIT_ACE)) //THEN //Set NewACE to ACE //Add INHERITED_ACE to NewACE.Flags //Add INHERIT_ONLY_ACE to NewACE.Flags //Append NewACE to InheritableACL //ENDIF //END FOR //ENDIF //RETURN concatenation of ExplicitACL and InheritableACL _ACL newAcl = new _ACL(); newAcl.AclRevision = acl.AclRevision; List<object> newAces = new List<object>(); #region Computes the explicit Acl if (acl.Aces != null) { foreach (object ace in acl.Aces) { object newAce = ObjectUtility.DeepClone(ace); _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(newAce, "Header"); if ((header.AceFlags & ACE_FLAGS.INHERIT_ONLY_ACE) == ACE_FLAGS.INHERIT_ONLY_ACE) { continue; } if (((header.AceFlags & ACE_FLAGS.CONTAINER_INHERIT_ACE) == ACE_FLAGS.CONTAINER_INHERIT_ACE && isContainerObject) || ((header.AceFlags & ACE_FLAGS.OBJECT_INHERIT_ACE) == ACE_FLAGS.OBJECT_INHERIT_ACE && (!isContainerObject))) { bool retVal = DtypUtility.ComputeInheritedAcefromParent(ref newAce, objectTypes); if (retVal) { newAces.Add(newAce); } } } } #endregion #region Compute the inheritable ACL if (isContainerObject && acl.AceCount >= 0 && acl.Aces != null) { foreach (object ace in acl.Aces) { object newAce = ObjectUtility.DeepClone(ace); _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(newAce, "Header"); if ((header.AceFlags & ACE_FLAGS.NO_PROPAGATE_INHERIT_ACE) == ACE_FLAGS.NO_PROPAGATE_INHERIT_ACE) { continue; } if ((header.AceFlags & ACE_FLAGS.CONTAINER_INHERIT_ACE) == ACE_FLAGS.CONTAINER_INHERIT_ACE || (header.AceFlags & ACE_FLAGS.OBJECT_INHERIT_ACE) == ACE_FLAGS.OBJECT_INHERIT_ACE) { header.AceFlags |= (ACE_FLAGS.INHERIT_ONLY_ACE | ACE_FLAGS.INHERITED_ACE); ObjectUtility.SetFieldValue(newAce, "Header", header); //Append NewACE to NewACL newAces.Add(newAce); } } } #endregion newAcl.Aces = newAces.ToArray(); newAcl.AceCount = (ushort)newAcl.Aces.Length; newAcl.AclSize = DtypUtility.CalculateAclSize(newAcl); return newAcl; }
/// <summary> /// ComputeInheritedACLfromCreator. MS-DTYP section 2.5.4.7 /// </summary> /// <param name="acl"> /// An ACL supplied in the security descriptor by the caller. /// </param> /// <param name="isContainerObject"> /// TRUE if the object is a container; otherwise, FALSE. /// </param> /// <param name="objectTypes"> /// An array of GUIDs for the object type being created. /// </param> /// <returns> /// The computed ACL that also includes the inherited ACEs. /// </returns> public static _ACL ComputeInheritedACLfromCreator( _ACL acl, bool isContainerObject, Guid[] objectTypes) { //Initialize ExplicitACL to Empty ACL //FOR each ACE in ACL DO //IF((ACE.Flags contains CONTAINER_INHERIT_ACE) AND //(IsContainerObject = TRUE))OR //((ACE.Flags contains OBJECT_INHERIT_ACE) AND //(IsContainerObject = FALSE)) //THEN // CASE ACE.Type OF // ALLOW: // DENY: // Set NewACE to ACE // Set NewACE.Flags to NULL // Append NewACE to ExplicitACL // OBJECT_ALLOW // OBJECT_DENY: // IF (ObjectTypes contains ACE.ObjectGUID) THEN // Set NewACE to ACE // Set NewACE.Flags to NULL // Append NewACE to ExplicitACL // ENDIF // ENDCASE //ENDIF //END FOR //Initialize InheritableACL to Empty ACL //IF (IsContainerObject = TRUE) THEN // FOR each ACE in ACL DO // IF((ACE.Flags contains CONTAINER_INHERIT_ACE) OR // (ACE.Flags contains OBJECT_INHERIT_ACE)) // THEN // Set NewACE to ACE // Add INHERIT_ONLY_ACE to NewACE.Flags // Append NewACE to InheritableACL // ENDIF // END FOR //ENDIF //RETURN concatenation of ExplicitACL and InheritableACL _ACL newAcl = new _ACL(); newAcl.AclRevision = acl.AclRevision; List<object> newAces = new List<object>(); #region Computes the explicit Acl if (acl.Aces != null) { foreach (object ace in acl.Aces) { object newAce = ObjectUtility.DeepClone(ace); _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(newAce, "Header"); ACCESS_OBJECT_ACE_Flags flags = ACCESS_OBJECT_ACE_Flags.None; ACE_TYPE aceType = header.AceType; if (header.AceType == ACE_TYPE.ACCESS_ALLOWED_OBJECT_ACE_TYPE || header.AceType == ACE_TYPE.ACCESS_DENIED_OBJECT_ACE_TYPE) { flags = (ACCESS_OBJECT_ACE_Flags)ObjectUtility.GetFieldValue(newAce, "Flags"); if ((flags & ACCESS_OBJECT_ACE_Flags.ACE_OBJECT_TYPE_PRESENT) != ACCESS_OBJECT_ACE_Flags.ACE_OBJECT_TYPE_PRESENT) { aceType = (header.AceType == ACE_TYPE.ACCESS_ALLOWED_OBJECT_ACE_TYPE) ? ACE_TYPE.ACCESS_ALLOWED_ACE_TYPE : ACE_TYPE.ACCESS_DENIED_ACE_TYPE; } } if (((header.AceFlags & ACE_FLAGS.CONTAINER_INHERIT_ACE) != 0 && isContainerObject) || ((header.AceFlags & ACE_FLAGS.OBJECT_INHERIT_ACE) != 0 && (!isContainerObject))) { bool retVal = DtypUtility.ComputeInheritedAcefromCreator(ref newAce, objectTypes); if (retVal) { newAces.Add(newAce); } } } } #endregion #region Compute the inheritable ACL if (isContainerObject) { if (acl.Aces != null) { foreach (object ace in acl.Aces) { object newAce = ObjectUtility.DeepClone(ace); _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(newAce, "Header"); if ((header.AceFlags & ACE_FLAGS.CONTAINER_INHERIT_ACE) == ACE_FLAGS.CONTAINER_INHERIT_ACE || (header.AceFlags & ACE_FLAGS.OBJECT_INHERIT_ACE) == ACE_FLAGS.OBJECT_INHERIT_ACE) { header.AceFlags |= ACE_FLAGS.INHERIT_ONLY_ACE; ObjectUtility.SetFieldValue(newAce, "Header", header); //Append NewACE to NewACL newAces.Add(newAce); } } } } #endregion newAcl.Aces = newAces.ToArray(); newAcl.AceCount = (ushort)newAcl.Aces.Length; newAcl.AclSize = DtypUtility.CalculateAclSize(newAcl); return newAcl; }
/// <summary> /// ComputeACL. MS-DTYP section 2.5.4.4 /// </summary> /// <param name="computeType">Enumeration of COMPUTE_DACL and COMPUTE_SACL.</param> /// <param name="parentAcl">ACL from the parent security descriptor.</param> /// <param name="parentControl">Control flags from the parent security descriptor.</param> /// <param name="creatorAcl">ACL supplied in the security descriptor by the creator.</param> /// <param name="creatorControl">Control flags supplied in the security descriptor by the creator.</param> /// <param name="isContainerObject">TRUE if the object is a container; otherwise, FALSE.</param> /// <param name="objectTypes">Array of GUIDs for the object type being created.</param> /// <param name="autoInheritFlags"> /// A set of bit flags that control how access control entries (ACEs) are /// inherited from ParentDescriptor. /// </param> /// <param name="genericMapping"> /// Mapping of generic permissions to resource manager-specific permissions supplied by the caller. /// </param> /// <param name="owner">Owner to use in substituting the CreatorOwner SID.</param> /// <param name="group">Group to use in substituting the CreatorGroup SID.</param> /// <param name="token">Token for default values.</param> /// <param name="computedControl">ComputedControl</param> /// <returns>Computed ACL</returns> public static _ACL? ComputeACL( AclComputeType computeType, _ACL? parentAcl, SECURITY_DESCRIPTOR_Control parentControl, _ACL? creatorAcl, SECURITY_DESCRIPTOR_Control creatorControl, bool isContainerObject, Guid[] objectTypes, SecurityDescriptorAutoInheritFlags autoInheritFlags, GenericMapping genericMapping, _SID owner, _SID group, Token token, out SECURITY_DESCRIPTOR_Control computedControl) { #region Pseudocode v20110329 //// The details of the algorithm to merge the parent ACL and the supplied ACL. //// The Control flags computed are slightly different based on whether it is the //// ACL in the DACL or the SACL field of the descriptor. //// The caller specifies whether it is a DACL or a SACL using the parameter, //// ComputeType. //Set ComputedACL to NULL //Set ComputedControl to NULL //CALL ContainsInheritableACEs WITH ParentACL RETURNING ParentHasInheritableACEs //IF ParentHasInheritableACEs = TRUE THEN // // The Parent ACL has inheritable ACEs. The Parent ACL should be used if no Creator // // ACL is supplied, or if the Creator ACL was supplied AND it is a default ACL based // // on object type information // IF(CreatorACL is not present) OR // ((CreatorACL is present) AND // (AutoInheritFlags contains DEFAULT_DESCRIPTOR_FOR_OBJECT)) // THEN // // Use only the inherited ACEs from the parent. First compute the ACL from the // // parent ACL, then clean it up by resolving the generic mappings etc. // CALL ComputeInheritedACLFromParent WITH // ACL set to ParentACL, // IsContainerObject set to IsContainerObject, // ObjectTypes set to ObjectTypes // RETURNING NextACL // CALL PostProcessACL WITH // ACL set to NextACL, // CopyFilter set to CopyInheritedAces, // Owner set to Owner, // Group set to Group, // GenericMapping set to GenericMapping // RETURNING FinalACL // Set ComputedACL to FinalACL // RETURN // ENDIF //IF ((CreatorACL is present) AND // (AutoInheritFlags does not contain DEFAULT_DESCRIPTOR_FOR_OBJECT)) //THEN // // Since a creator ACL is present, and we’re not defaulting the // // descriptor, determine which ACEs are inherited and compute the new ACL // CALL PreProcessACLFromCreator WITH // ACL set to CreatorACL // RETURNING PreACL // CALL ComputeInheritedACLFromCreator WITH // ACL set to PreACL, // IsContainerObject set to IsContainerObject, // ObjectTypes set to ObjectTypes // RETURNING TmpACL // // Special handling for DACL types of ACLs // IF (ComputeType = DACL_COMPUTE) THEN // // DACL-specific operations // IF (CreatorControl does not have DACL_PROTECTED flag set) AND // (AutoInheritFlags contains DACL_AUTO_INHERIT) // THEN // // We’re not working from a protected DACL, and we’re supposed to // // allow automatic inheritance. Compute the inherited ACEs from // // Parent ACL this time, and append that to the ACL that we’re building // CALL ComputeInheritedACLFromParent WITH // ACL set to ParentACL, // IsContainerObject set to IsContainerObject, // ObjectTypes set to ObjectTypes // RETURNING InheritedParentACL // Append InheritedParentACL.ACEs to TmpACL.ACE // Set DACL_AUTO_INHERITED flag in ComputedControl // ENDIF // ENDIF // DACL-Specific behavior // IF (ComputeType = SACL_COMPUTE) THEN // // Similar to the above, perform SACL-specific operations // IF (CreatorControl does not have SACL_PROTECTED flag set) AND // (AutoInheritFlags contains SACL_AUTO_INHERIT flag) // THEN // // We’re not working from a protected SACL, and we’re supposed to // // allow automatic inheritance. Compute the inherited ACEs from // // Parent ACL this time, and append that to the ACL that we’re building // CALL ComputeInheritedACLFromParent WITH // ACL set to ParentACL, // IsContainerObject set to IsContainerObject, // ObjectTypes set to ObjectTypes // RETURNING InheritedParentACL // Append InheritedParentACL.ACEs to TmpACL.ACE // Set SACL_AUTO_INHERITED flag in ComputedControl // ENDIF // ENDIF // SACL-Specific behavior // CALL PostProcessACL WITH // ACL set to TmpACL, // CopyFilter set to CopyInheritedAces, // Owner set to Owner, // Group set to Group, // GenericMapping set to GenericMapping // RETURNING ProcessedACL // Set ComputedACL to ProcessedACL // RETURN //ENDIF // CreatorACL is present //ELSE // ParentACL does not contain inheritable ACEs // IF CreatorACL = NULL THEN // // No ACL supplied for the object // IF (ComputeType = DACL_COMPUTE) THEN // Set TmpACL to Token.DefaultDACL // ELSE // // No default for SACL; left as NULL // ENDIF // ELSE // // Explicit ACL was supplied for the object - either default or not. // // In either case, use it for the object, since there are no inherited ACEs. // CALL PreProcessACLFromCreator WITH CreatorACL // RETURNING TmpACL // ENDIF // CALL PostProcessACL WITH // ACL set to TmpACL, // CopyFilter set to CopyAllAces, // Owner set to Owner, // Group set to Group, // GenericMapping set to GenericMapping // RETURNING ProcessedACL // Set ComputedACL to ProcessedACL //ENDIF //// END ComputeACL #endregion _ACL? computedACL = null; computedControl = SECURITY_DESCRIPTOR_Control.None; _ACL tmpAcl = new _ACL(); _ACL preAcl = new _ACL(); if (parentAcl != null && ContainsInheritableACEs(parentAcl.Value)) { // ParentACL contains inheritable ACEs if ((creatorAcl == null) || ((creatorAcl != null) && (autoInheritFlags & SecurityDescriptorAutoInheritFlags.DEFAULT_DESCRIPTOR_FOR_OBJECT) == SecurityDescriptorAutoInheritFlags.DEFAULT_DESCRIPTOR_FOR_OBJECT)) { // Use only the inherited ACEs from the parent _ACL nextAcl = ComputeInheritedACLfromParent(parentAcl.Value, isContainerObject, objectTypes); _ACL finalAcl = PostProcessACL(nextAcl, CopyFilter.CopyInheritedAces, owner, group, genericMapping); computedACL = finalAcl; } else { preAcl = PreProcessACLfromCreator(creatorAcl.Value); tmpAcl = ComputeInheritedACLfromCreator(preAcl, isContainerObject, objectTypes); _ACL? inheritedAcl = null; if ((computeType == AclComputeType.COMPUTE_DACL) && (creatorControl & SECURITY_DESCRIPTOR_Control.DACLProtected) == SECURITY_DESCRIPTOR_Control.None && (autoInheritFlags & SecurityDescriptorAutoInheritFlags.DACL_AUTO_INHERIT) == SecurityDescriptorAutoInheritFlags.DACL_AUTO_INHERIT) { // Compute the inherited ACEs from the parent inheritedAcl = ComputeInheritedACLfromParent( parentAcl.Value, isContainerObject, objectTypes); computedControl |= SECURITY_DESCRIPTOR_Control.DACLAutoInherited; } else if ((computeType == AclComputeType.COMPUTE_SACL) && (creatorControl & SECURITY_DESCRIPTOR_Control.SACLProtected) == SECURITY_DESCRIPTOR_Control.None && (autoInheritFlags & SecurityDescriptorAutoInheritFlags.SACL_AUTO_INHERIT) == SecurityDescriptorAutoInheritFlags.SACL_AUTO_INHERIT) { // Compute the inherited ACEs from the parent inheritedAcl = ComputeInheritedACLfromParent( parentAcl.Value, isContainerObject, objectTypes); computedControl |= SECURITY_DESCRIPTOR_Control.SACLAutoInherited; } if (inheritedAcl != null) { List<object> tmpAces = new List<object>(); tmpAces.AddRange(tmpAcl.Aces); tmpAces.AddRange(inheritedAcl.Value.Aces); tmpAcl.Aces = tmpAces.ToArray(); tmpAcl.AceCount = (ushort)tmpAcl.Aces.Length; tmpAcl.AclSize = DtypUtility.CalculateAclSize(tmpAcl); } computedACL = PostProcessACL(tmpAcl, CopyFilter.CopyInheritedAces, owner, group, genericMapping); } } else { // ParentACL does not contain inheritable ACEs if (creatorAcl == null) { if (computeType == AclComputeType.COMPUTE_DACL) { tmpAcl = token.DefaultDACL; } else { //No default for SACL;left as NULL return null; } } else { // Explicit ACL was supplied for the object - either default or not. // In either case, use it for the object, since there are no inherited ACEs. tmpAcl = PreProcessACLfromCreator(creatorAcl.Value); } computedACL = PostProcessACL(tmpAcl, CopyFilter.CopyAllAces, owner, group, genericMapping); } if (computedACL != null) { computedControl |= ((computeType == AclComputeType.COMPUTE_DACL) ? SECURITY_DESCRIPTOR_Control.DACLPresent : SECURITY_DESCRIPTOR_Control.SACLPresent); } return computedACL; }