/// <summary> /// Access Check Algorithm. MS-DTYP section 2.5.4.1 /// </summary> /// <param name="securityDescriptor"> /// SECURITY_DESCRIPTOR structure that is assigned to the object. /// </param> /// <param name="token"> /// Token is an authorization context containing all SIDs /// that represent the security principal /// </param> /// <param name="accessRequestMask"> /// Set of permissions requested on the object. /// </param> /// <param name="objectTree"> /// A tree representation of the hierarchy of objects for which /// to check access. Each node represents an object with two values. /// A GUID that represents the object itself and a value called /// Remaining, which indicates the user rights request for that /// node that have not yet been satisfied. It can be null. /// </param> /// <param name="principalSelfSubstitudeSid"> /// A SID that logically replaces the SID in any ACE that contains /// the well-known PRINCIPAL_SELF SID. It can be null. /// </param> /// <returns> /// Returns TRUE if access is allowed. Otherwise, it returns FALSE if access is denied. /// </returns> /// <exception cref="ArgumentException"> /// Thrown when the Dacl field of securityDescriptor doesn't exist, but the DACLPresent flag is set. /// Thrown when the Revision field of securityDescriptor is invalid /// </exception> public static bool AccessCheck( _SECURITY_DESCRIPTOR securityDescriptor, Token token, uint accessRequestMask, AccessCheckObjectTree objectTree, _SID? principalSelfSubstitudeSid) { //MS-ADTS Section 5.1.3.3.1 Null vs. Empty DACLs //The presence of a NULL DACL in the nTSecurityDescriptor attribute of an object grants full //access to the object to any principal that requests it; normal access checks are not performed //with respect to the object. if (securityDescriptor.Revision != 0x1) { throw new ArgumentException("The Revision field is invalid.", "securityDescriptor"); } if ((securityDescriptor.Control & SECURITY_DESCRIPTOR_Control.DACLPresent) == SECURITY_DESCRIPTOR_Control.None) { return true; } else if (securityDescriptor.Dacl == null) { throw new ArgumentException( "The Dacl field of securityDescriptor doesn't exist, but the DACLPresent flag is set.", "securityDescriptor"); } //Pscudocode // //Set DACL to SecurityDescriptor Dacl field //Set RemainingAccess to Access Request mask // //IF RemainingAccess contains ACCESS_SYSTEM_SECURITY access flag THEN //IF Token.Privileges contains SeSecurityPrivilege THEN //Remove ACCESS_SYSTEM_SECURITY access bit from RemainingAccess //END IF //END IF // //IF RemainingAccess contains WRITE_OWNER access bit THEN //IF Token.Privileges contains SeTakeOwnershipPrivilege THEN //Remove WRITE_OWNER access bit from RemainingAccess //END IF //END IF //-- the owner of an object is always granted READ_CONTROL and WRITE_DAC. //CALL SidInToken( Token, SecurityDescriptor.Owner, PrincipalSelfSubst) //IF SidInToken returns True THEN //Remove READ_CONTROL and WRITE_DAC from RemainingAccess //END IF _ACL? dacl = securityDescriptor.Dacl; uint remainingAccess = accessRequestMask; AccessCheckObjectTree localTree = new AccessCheckObjectTree(); Guid[] allNodes = new Guid[] { }; if ((remainingAccess & ACCESS_MASK_ACCESS_SYSTEM_SECURITY) != 0 && token.Privileges != null) { foreach (_LUID privilege in token.Privileges) { if (ObjectUtility.DeepCompare(privilege, GetPrivilegeLuid(PrivilegeName.SE_SECURITY_NAME))) { remainingAccess &= ~ACCESS_MASK_ACCESS_SYSTEM_SECURITY; } } } if ((remainingAccess & ACCESS_MASK_WRITE_OWNER) != 0 && token.Privileges != null) { foreach (_LUID privilege in token.Privileges) { if (ObjectUtility.DeepCompare(privilege, GetPrivilegeLuid(PrivilegeName.SE_TAKE_OWNERSHIP_NAME))) { remainingAccess &= ~ACCESS_MASK_WRITE_OWNER; } } } if (securityDescriptor.OwnerSid != null && SidInToken(token, securityDescriptor.OwnerSid.Value, principalSelfSubstitudeSid)) { remainingAccess &= ~(uint)(ACCESS_MASK_READ_CONTROL | ACCESS_MASK_WRITE_DAC); } //IF Object Tree is not NULL THEN //Set LocalTree to Object Tree //FOR each node in LocalTree DO //Set node.Remaining to RemainingAccess //END FOR //END IF if (objectTree != null && objectTree.Root != null) { localTree = (AccessCheckObjectTree)ObjectUtility.DeepClone(objectTree); List<Guid> tmpList = new List<Guid>(); tmpList.Add(localTree.Root.Value); tmpList.AddRange(localTree.GetDescendentNodes(localTree.Root.Value)); allNodes = tmpList.ToArray(); foreach (Guid node in allNodes) { localTree.SetTreeNodeData(node, remainingAccess); } } //FOR each ACE in DACL DO //IF ACE.flag does not contain INHERIT_ONLY_ACE THEN //CASE ACE.Type OF //CASE Allow Access: //CALL SidInToken( Token, ACE.Sid, and PrincipalSelfSubst ) //IF SidInToken returns True THEN // Remove ACE.AccessMask from RemainingAccess // FOR each node in LocalTree DO // Remove ACE.AccessMask from node.Remaining //END FOR //END IF //CASE Deny Access: //CALL SidInToken( Token, ACE.Sid, PrincipalSelfSubst ) //IF SidInToken returns True THEN // IF any bit of RemainingAccess is in ACE.AccessMask THEN // Return access_denied //END IF //END IF //CASE Object Allow Access: //CALL SidInToken( Token, ACE.Sid, PrincipalSelfSubst ) //IF SidInToken returns True THEN // IF ACE.Object is contained in LocalTree THEN // Locate node n in LocalTree such that // n.GUID is the same as ACE.Object // Remove ACE.AccessMask from n.Remaining // FOR each node ns such that ns is a descendent of n DO // Remove ACE.AccessMask from ns.Remaining // END FOR // FOR each node np such that np is an ancestor of n DO // Set np.Remaining = np.Remaining or np-1.Remaining //END FOR //END IF //END IF //CASE Object Deny Access: //CALL SidInToken( Token, ACE.Sid, PrincipalSelfSubst ) //IF SidInToken returns True THEN // Locate node n in LocalTree such that // n.GUID is the same as ACE.Object // IF n exists THEN // If any bit of n.Remaining is in ACE.AccessMask THEN // Return access_denied //END IF //END IF //END IF //END CASE //END IF //END FOR if (dacl.Value.Aces != null) { foreach (object ace in dacl.Value.Aces) { _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(ace, "Header"); _SID sid = (_SID)ObjectUtility.GetFieldValue(ace, "Sid"); if ((header.AceFlags & ACE_FLAGS.INHERIT_ONLY_ACE) == ACE_FLAGS.INHERIT_ONLY_ACE || !SidInToken(token, sid, principalSelfSubstitudeSid)) { continue; } bool ret = DtypUtility.AceAccessCheck(ace, ref remainingAccess, ref localTree, allNodes); if (ret == false) { return false; } } } //IF RemainingAccess = 0 THEN //Return success //Else //Return access_denied //END IF bool status; if (objectTree != null && objectTree.Root != null) { status = (localTree.GetTreeNodeData(localTree.Root.Value) == 0); } else { status = (remainingAccess == 0); } return status; }
/// <summary> /// A support function, SidInToken, takes the authorization context, /// a SID (referenced below as the SidToTest parameter), and an optional /// PrincipalSelfSubstitute parameter, and returns TRUE if the SidToTest /// is present in the authorization context; otherwise, it returns FALSE. /// The well-known SID PRINCIPAL_SELF, if passed as SidToTest, is replaced /// by the PrincipalSelfSubstitute SID prior to the examination of the /// authorization context. MS-DTYP section 2.5.4.1 /// </summary> /// <param name="token"> /// Token is an authorization context containing all SIDs /// that represent the security principal /// </param> /// <param name="sidToTest"> /// The SID for which to search in Token /// </param> /// <param name="principalSelfSubstitute"> /// a SID with which SidToTest may be replaced /// </param> /// <returns> /// Returns TRUE if the SidToTest is present in the authorization context; /// otherwise, it returns FALSE. /// </returns> /// <exception cref="ArgumentException"> /// Thrown when the well-known SID PRINCIPAL_SELF, if passed as SidToTest, but /// principalSelfSubstitute does't exist. /// </exception> public static bool SidInToken( Token token, _SID sidToTest, _SID? principalSelfSubstitute) { // //Pseudocode syntax // //-- //-- On entry //-- Token is an authorization context containing all SIDs //-- that represent the security principal //-- SidToTest, the SID for which to search in Token //-- PrincipalSelfSubstitute, a SID with which SidToTest may be //-- replaced //IF SidToTest is the Well Known SID PRINCIPAL_SELF THEN //set SidToTest to be PrincipalSelfSubstitute //END IF //FOR EACH SID s in Token DO //IF s equals SidToTest THEN //return TRUE //END IF //END FOR //Return FALSE //END-SUBROUTINE if (ObjectUtility.DeepCompare(GetWellKnownSid(WellKnownSid.PRINCIPAL_SELF, null), sidToTest)) { if (principalSelfSubstitute != null) { sidToTest = (_SID)principalSelfSubstitute; } else { throw new ArgumentException("The principalSelfSubstitute doesn't exist", "principalSelfSubstitute"); } } if (token.Sids != null) { foreach (_SID sid in token.Sids) { if (ObjectUtility.DeepCompare(sid, sidToTest)) { return true; } } } return false; }
/// <summary> /// Create SecurityDescriptor in absolute format. MS-DTYP section 2.5.4.3 /// </summary> /// <param name="parentDescriptor"> /// Security descriptor for the parent (container) object of the new object. /// If the object has no parent, this parameter is null. /// </param> /// <param name="creatorDescriptor"> /// Security descriptor for the new object provided by the creator of the object. /// Caller can pass null. /// </param> /// <param name="isContainerObject"> /// TRUE when the object is a container; otherwise, FALSE. /// </param> /// <param name="objectTypes"> /// An array of pointers to GUID structures that identify the object types or /// classes of the object associated with NewDescriptor (the return value). /// For Active Directory objects, this array contains pointers to the class /// GUIDs of the object's structural class and all attached auxiliary classes. /// If the object for which this descriptor is being created does not have a GUID, /// this field MUST be set to null. /// </param> /// <param name="autoInheritFlags"> /// A set of bit flags that control how access control entries (ACEs) are /// inherited from ParentDescriptor. /// </param> /// <param name="token"> /// Token supplied by the caller for default security information for the new object. /// </param> /// <param name="genericMapping"> /// Mapping of generic permissions to resource manager-specific permissions /// supplied by the caller. /// </param> /// <returns> /// Output security descriptor for the object computed by the algorithm. /// </returns> /// <exception cref="ArgumentException"> /// Thrown when the OwnerSid or GroupSid field of parentDescriptor is null, but /// autoInheritFlags is set to DEFAULT_OWNER_FROM_PARENT or DEFAULT_GROUP_FROM_PARENT. /// Thrown when the Dacl field of parentDescriptor doesn't exist, but the DACLPresent flag is set. /// Thrown when the Sacl field of parentDescriptor doesn't exist, but the SP flag is set. /// </exception> public static _SECURITY_DESCRIPTOR CreateSecurityDescriptor( _SECURITY_DESCRIPTOR? parentDescriptor, _SECURITY_DESCRIPTOR? creatorDescriptor, bool isContainerObject, Guid[] objectTypes, SecurityDescriptorAutoInheritFlags autoInheritFlags, Token token, GenericMapping genericMapping) { const byte DEFAULT_REVISION = 1; _SECURITY_DESCRIPTOR newDescriptor = new _SECURITY_DESCRIPTOR(); newDescriptor.Revision = DEFAULT_REVISION; //Compute the Owner field (v20100908) //IF CreatorDescriptor.Owner is NULL THEN //IF AutoInheritFlags contains DEFAULT_OWNER_FROM_PARENT THEN //Set NewDescriptor.Owner to ParentDescriptor.Owner //ELSE //Set NewDescriptor.Owner to Token.SIDs[Token.OwnerIndex] //ENDIF //ELSE //Set NewDescriptor.Owner to CreatorDescriptor.Owner //ENDIF if (creatorDescriptor != null) { newDescriptor.OwnerSid = creatorDescriptor.Value.OwnerSid; } else if ((autoInheritFlags & SecurityDescriptorAutoInheritFlags.DEFAULT_OWNER_FROM_PARENT) == SecurityDescriptorAutoInheritFlags.DEFAULT_OWNER_FROM_PARENT) { if (parentDescriptor != null) { newDescriptor.OwnerSid = parentDescriptor.Value.OwnerSid; } else { throw new ArgumentException( "The parentDescriptor doesn't exist, but DEFAULT_OWNER_FROM_PARENT flag is set.", "parentDescriptor"); } } else { newDescriptor.OwnerSid = token.Sids[token.OwnerIndex]; } //Compute the Group field //IF CreatorDescriptor.Group is NULL THEN //IF AutoInheritFlags contains DEFAULT_GROUP_FROM_PARENT THEN //Set NewDescriptor.Group to ParentDescriptor.Group //ELSE //Set NewDescriptor.Group to Token.SIDs[Token.PrimaryGroup] //ENDIF //ELSE //Set NewDescriptor.Group to CreatorDescriptor.Group //ENDIF if (creatorDescriptor != null) { newDescriptor.GroupSid = creatorDescriptor.Value.GroupSid; } else if ((autoInheritFlags & SecurityDescriptorAutoInheritFlags.DEFAULT_GROUP_FROM_PARENT) == SecurityDescriptorAutoInheritFlags.DEFAULT_GROUP_FROM_PARENT) { if (parentDescriptor != null) { newDescriptor.GroupSid = parentDescriptor.Value.GroupSid; } else { throw new ArgumentException( "The parentDescriptor doesn't exist, but DEFAULT_GROUP_FROM_PARENT flag is set.", "parentDescriptor"); } } else { newDescriptor.GroupSid = token.Sids[token.PrimaryGroup]; } _ACL? parentDacl = null; _ACL? parentSacl = null; SECURITY_DESCRIPTOR_Control parentControl = SECURITY_DESCRIPTOR_Control.None; _ACL? creatorDacl = null; _ACL? creatorSacl = null; SECURITY_DESCRIPTOR_Control creatorControl = SECURITY_DESCRIPTOR_Control.None; #region Check Sacl or Dacl filed against SP or DACLPresent flag in the control field. if (parentDescriptor != null) { parentControl = parentDescriptor.Value.Control; if ((parentDescriptor.Value.Control & SECURITY_DESCRIPTOR_Control.DACLPresent) == SECURITY_DESCRIPTOR_Control.DACLPresent) { if (parentDescriptor.Value.Dacl == null) { throw new ArgumentException( "The Dacl field of parentDescriptor doesn't exist, but the DACLPresent flag is set.", "parentDescriptor"); } else { parentDacl = parentDescriptor.Value.Dacl; } } if ((parentDescriptor.Value.Control & SECURITY_DESCRIPTOR_Control.SACLPresent) == SECURITY_DESCRIPTOR_Control.SACLPresent) { if (parentDescriptor.Value.Sacl == null) { throw new ArgumentException( "The Sacl field of parentDescriptor doesn't exist, but the SP flag is set.", "parentDescriptor"); } else { parentSacl = parentDescriptor.Value.Sacl; } } } if (creatorDescriptor != null) { creatorControl = creatorDescriptor.Value.Control; if ((creatorDescriptor.Value.Control & SECURITY_DESCRIPTOR_Control.DACLPresent) == SECURITY_DESCRIPTOR_Control.DACLPresent) { if (creatorDescriptor.Value.Dacl == null) { throw new ArgumentException( "The Dacl field of creatorDescriptor doesn't exist, but the DACLPresent flag is set.", "creatorDescriptor"); } else { creatorDacl = creatorDescriptor.Value.Dacl; } } if ((creatorDescriptor.Value.Control & SECURITY_DESCRIPTOR_Control.SACLPresent) == SECURITY_DESCRIPTOR_Control.SACLPresent) { if (creatorDescriptor.Value.Sacl == null) { throw new ArgumentException( "The Sacl field of creatorDescriptor doesn't exist, but the SP flag is set.", "creatorDescriptor"); } else { creatorSacl = creatorDescriptor.Value.Sacl; } } } #endregion //Compute the DACL //CALL ComputeACL WITH //COMPUTE_DACL, ParentDescriptor.DACL, ParentDescriptor.Control, //CreatorDescriptor.DACL,CreatorDescriptor.Control //IsContainerObject, ObjectTypes, GenericMapping, //NewDescriptor.Owner, NewDescriptor.Group, Token //RETURNING NewDACL, NewControl //Set NewDescriptor.DACL to NewDACL //Set NewDescriptor.Control to NewControl SECURITY_DESCRIPTOR_Control newControl = SECURITY_DESCRIPTOR_Control.None; _ACL? newDacl = ComputeACL( AclComputeType.COMPUTE_DACL, parentDacl, parentControl, creatorDacl, creatorControl, isContainerObject, objectTypes, autoInheritFlags, genericMapping, newDescriptor.OwnerSid.Value, newDescriptor.GroupSid.Value, token, out newControl); newDescriptor.Dacl = newDacl; newDescriptor.Control = newControl; //Compute the SACL //CALL ComputeACL WITH //COMPUTE_SACL, ParentDescriptor.SACL, ParentDescriptor.Control, //CreatorDescriptor.SACL,CreatorDescriptor.Control //IsContainerObject, ObjectTypes, GenericMapping, //NewDescriptor.Owner, NewDescriptor.Group, Token //RETURNING NewSACL, NewControl //Set NewDescriptor.SACLto NewSACL //Set NewDescriptor.Control to (NewDescriptor.Control OR NewControl) //RETURN NewDescriptor _ACL? newSacl = ComputeACL( AclComputeType.COMPUTE_SACL, parentSacl, parentControl, creatorSacl, creatorControl, isContainerObject, objectTypes, autoInheritFlags, genericMapping, newDescriptor.OwnerSid.Value, newDescriptor.GroupSid.Value, token, out newControl); newDescriptor.Sacl = newSacl; newDescriptor.Control |= newControl; //New SecurityDescriptor is in absolute format. newDescriptor.Control = newDescriptor.Control & (~SECURITY_DESCRIPTOR_Control.SelfRelative); return newDescriptor; }
/// <summary> /// MandatoryIntegrityCheck. MS-DTYP section 2.5.4.1 /// </summary> /// <param name="tokenIntegritySID"> /// Mandatory Integrity SID in the Token /// </param> /// <param name="aceIntegritySID"> /// Mandatory Integrity label SID in the Security descriptor of the object /// </param> /// <param name="mandatoryInformation"> /// Output of the function describing the allowable bits for the caller /// </param> /// <param name="token"> /// Authorization context /// </param> /// <param name="objectSecurityDescriptor"> /// SECURITY_DESCRIPTOR structure that is assigned to the object /// </param> /// <returns>True if check is done successfully; otherwise, false</returns> public static bool MandatoryIntegrityCheck( _SID tokenIntegritySID, _SID aceIntegritySID, out uint mandatoryInformation, Token token, _SECURITY_DESCRIPTOR objectSecurityDescriptor) { //Set TokenPolicy to Token MandatoryPolicy field //Set ObjectIntegrityACE to SecurityDescriptor ObjectIntegrity ACE field //Set ObjectIntegrityAceMask to SecurityDescriptor ObjectIntegrity Accessmask field // //IF TokenPolicy.Policy EQUAL TOKEN_MANDATORY_POLICY_OFF OR //TokenPolicy.Policy EQUAL TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN THEN //Set MandatoryInformation.AllowedAccess to GENERIC_ALL //Return success //END IF // //IF ObjectIntegrityACE.AceFlag NOT EQUAL INHERIT_ONLY_ACE THEN //Set AceMask to ObjectIintegrityACE.AccessMask //Set AceIntegritysid to ObjectIntegrityACE.TrusteeSid //ELSE //Set AceMask to SYSTEM_MANDATORY_LABEL_NO_WRITE_UP //--The DefaultMandatorySid is derived from policy managed in an //--implementation specific manner. The SID for ML_MEDIUM is used by //--Windows. //Set AceIntegritysid to DefaultMandatorySid //END IF TokenMandatoryPolicyValue tokenPolicy = token.MandatoryPolicy; _SYSTEM_MANDATORY_LABEL_ACE? objectIntegrityACE = null; mandatoryInformation = 0; bool tokenDominates; if (tokenPolicy == TokenMandatoryPolicyValue.TOKEN_MANDATORY_POLICY_OFF || tokenPolicy == TokenMandatoryPolicyValue.TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN) { mandatoryInformation = ACCESS_MASK_GENERIC_ALL; return true; } if ((objectSecurityDescriptor.Control & SECURITY_DESCRIPTOR_Control.SACLPresent) == SECURITY_DESCRIPTOR_Control.SACLPresent && objectSecurityDescriptor.Sacl != null) { if (objectSecurityDescriptor.Sacl.Value.Aces != null) { foreach (object ace in objectSecurityDescriptor.Sacl.Value.Aces) { _SID sid = (_SID)ObjectUtility.GetFieldValue(ace, "Sid"); if (ObjectUtility.DeepCompare(sid, aceIntegritySID)) { objectIntegrityACE = (_SYSTEM_MANDATORY_LABEL_ACE)ace; } } } } SYSTEM_MANDATORY_LABEL_ACE_Mask objectIntegrityAceMask; _SID aceIntegritySid; if (objectIntegrityACE != null && objectIntegrityACE.Value.Header.AceFlags != ACE_FLAGS.INHERIT_ONLY_ACE) { objectIntegrityAceMask = objectIntegrityACE.Value.Mask; aceIntegritySid = objectIntegrityACE.Value.Sid; } else { objectIntegrityAceMask = SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_WRITE_UP; //The DefaultMandatorySid is derived from policy managed in an //implementation specific manner. The SID for ML_MEDIUM is used by //Windows. aceIntegritySid = GetWellKnownSid(WellKnownSid.ML_MEDIUM, null); } // //Note:SidDominates is removed from the current function, because it's declared but not used. // //CALL sidEqual(AceIntegritysid, TokenIntegritysid) //IF AceIntegritySid EQUALS Token.MandatoryIntegritySid THEN //Set TokenDominates to TRUE //Set ObjectDominates to TRUE //ELSE //CALL SidDominates (Token.MandatoryIntegritySid, AceIntegritysid) //IF SidDominates returns TRUE THEN //Set TokenDominates to TRUE //ELSE //Set TokenDominates to FALSE //END IF //Set ObjectDominates to NOT(TokenDominates) //END IF tokenDominates = SidDominates((_SID)token.IntegrityLevelSid, aceIntegritySid); //IF TokenPolicy EQUAL TOKEN_MANDATORY_POLICY_NO_WRITE_UP THEN //Add READ to MandatoryInformation.AllowedAccess //Add EXECUTE to MandatoryInformation.AllowedAccess //IF TokenDominates is TRUE THEN //Add WRITE to MandatoryInformation.AllowedAccess //END IF //END IF // //IF TokenDominates is FALSE THEN //IF ObjectIntegrityAceMask & SYSTEM_MANDATORY_LABEL_NO_READ_UP THEN //Remove READ from MandatoryInformation.AllowedAccess //END IF //IF ObjectIntegrityAceMask & SYSTEM_MANDATORY_LABEL_NO_WRITE_UP THEN //Remove WRITE from MandatoryInformation.AllowedAccess //END IF //IF ObjectIntegrityAceMask & SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP THEN //Remove EXECUTE from MandatoryInformation.AllowedAccess //END IF //END IF // //IF Token.Privileges contains SeRelabelPrivilegeTHEN //Add WRITE_OWNER to MandatoryInformation.AllowedAccess //END IF if (tokenPolicy == TokenMandatoryPolicyValue.TOKEN_MANDATORY_POLICY_NO_WRITE_UP) { mandatoryInformation |= ACCESS_MASK_GENERIC_READ; mandatoryInformation |= ACCESS_MASK_GENERIC_EXECUTE; if (tokenDominates) { mandatoryInformation |= ACCESS_MASK_GENERIC_WRITE; } } if (!tokenDominates) { if ((objectIntegrityAceMask & SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_READ_UP) == SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_READ_UP) { mandatoryInformation &= ~ACCESS_MASK_GENERIC_READ; } if ((objectIntegrityAceMask & SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_WRITE_UP) == SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_WRITE_UP) { mandatoryInformation &= ~ACCESS_MASK_GENERIC_WRITE; } if ((objectIntegrityAceMask & SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP) == SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP) { mandatoryInformation &= ~ACCESS_MASK_GENERIC_EXECUTE; } } if (token.Privileges != null) { foreach (_LUID privilege in token.Privileges) { if (ObjectUtility.DeepCompare(privilege, GetPrivilegeLuid(PrivilegeName.SE_RELABEL_NAME))) { mandatoryInformation |= ACCESS_MASK_WRITE_OWNER; } } } return true; }
/// <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; }