/// <summary> /// Update the Offset* fields of the input _SECURITY_DESCRIPTOR structure. /// </summary> /// <param name="securityDescriptor">The security descriptor to be updated.</param> /// <returns>The encoded byte array.</returns> public static void UpdateSecurityDescriptor(ref _SECURITY_DESCRIPTOR sd) { // Revision (1 byte) + Sbz1 (1 byte) + Control (2 bytes) + OffsetOwner (4 bytes) + OffsetGroup (4 bytes) + // OffsetSacl (4 bytes) + OffsetDacl (4 bytes) int offset = 20; if (sd.OwnerSid != null) { sd.OffsetOwner = (uint)offset; offset += TypeMarshal.GetBlockMemorySize<_SID>(sd.OwnerSid.Value); } else { sd.OffsetOwner = 0; } if (sd.GroupSid != null) { sd.OffsetGroup = (uint)offset; offset += TypeMarshal.GetBlockMemorySize<_SID>(sd.GroupSid.Value); } else { sd.OffsetGroup = 0; } if (sd.Sacl != null) { sd.OffsetSacl = (uint)offset; offset += DtypUtility.EncodeAcl(sd.Sacl.Value).Length; } else { sd.OffsetSacl = 0; } if (sd.Dacl != null) { sd.OffsetDacl = (uint)offset; offset += DtypUtility.EncodeAcl(sd.Dacl.Value).Length; } else { sd.OffsetDacl = 0; } }
/// <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> /// Convert _SECURITY_DESCRIPTOR to SDDL string. /// </summary> /// <param name="securityDescriptor">_SECURITY_DESCRIPTOR to convert.</param> /// <returns>SDDL string.</returns> public static string ToSddlString(_SECURITY_DESCRIPTOR securityDescriptor) { byte[] securityDescriptorBytes = DtypUtility.EncodeSecurityDescriptor(securityDescriptor); RawSecurityDescriptor rawSecurityDescriptor = new RawSecurityDescriptor(securityDescriptorBytes, 0); return rawSecurityDescriptor.GetSddlForm(AccessControlSections.All); }
/// <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> /// Encode the _SECURITY_DESCRIPTOR structure into byte array, according to TD specification. /// </summary> /// <param name="securityDescriptor">The security descriptor to be retrieved.</param> /// <returns>The encoded byte array.</returns> public static byte[] EncodeSecurityDescriptor(_SECURITY_DESCRIPTOR securityDescriptor) { if ((securityDescriptor.Control & SECURITY_DESCRIPTOR_Control.SelfRelative) == 0) { securityDescriptor = DtypUtility.CreateSecurityDescriptor( securityDescriptor.Control, securityDescriptor.OwnerSid, securityDescriptor.GroupSid, securityDescriptor.Sacl, securityDescriptor.Dacl); } List<byte> byteArray = new List<byte>(); byteArray.Add(securityDescriptor.Revision); byteArray.Add(securityDescriptor.Sbz1); byteArray.AddRange(TypeMarshal.ToBytes<SECURITY_DESCRIPTOR_Control>(securityDescriptor.Control)); byteArray.AddRange(TypeMarshal.ToBytes<uint>(securityDescriptor.OffsetOwner)); byteArray.AddRange(TypeMarshal.ToBytes<uint>(securityDescriptor.OffsetGroup)); byteArray.AddRange(TypeMarshal.ToBytes<uint>(securityDescriptor.OffsetSacl)); byteArray.AddRange(TypeMarshal.ToBytes<uint>(securityDescriptor.OffsetDacl)); if (securityDescriptor.OwnerSid != null) { byteArray.AddRange(TypeMarshal.ToBytes<_SID>(securityDescriptor.OwnerSid.Value)); } if (securityDescriptor.GroupSid != null) { byteArray.AddRange(TypeMarshal.ToBytes<_SID>(securityDescriptor.GroupSid.Value)); } if (securityDescriptor.Sacl != null) { byteArray.AddRange(DtypUtility.EncodeAcl(securityDescriptor.Sacl.Value)); } if (securityDescriptor.Dacl != null) { byteArray.AddRange(DtypUtility.EncodeAcl(securityDescriptor.Dacl.Value)); } return byteArray.ToArray(); }
/// <summary> /// Decode the specified buffer into the _SECURITY_DESCRIPTOR structure. /// </summary> /// <param name="buffer">The byte array to be decoded.</param> /// <returns>The _SECURITY_DESCRIPTOR structure.</returns> public static _SECURITY_DESCRIPTOR DecodeSecurityDescriptor(byte[] buffer) { int offset = 0; _SECURITY_DESCRIPTOR securityDescriptor = new _SECURITY_DESCRIPTOR(); securityDescriptor.Revision = buffer[offset]; offset += sizeof(byte); securityDescriptor.Sbz1 = buffer[offset]; offset += sizeof(byte); securityDescriptor.Control = TypeMarshal.ToStruct<SECURITY_DESCRIPTOR_Control>( ArrayUtility.SubArray(buffer, offset, sizeof(SECURITY_DESCRIPTOR_Control))); offset += sizeof(ushort); securityDescriptor.OffsetOwner = TypeMarshal.ToStruct<uint>( ArrayUtility.SubArray(buffer, offset, sizeof(uint))); offset += sizeof(uint); securityDescriptor.OffsetGroup = TypeMarshal.ToStruct<uint>( ArrayUtility.SubArray(buffer, offset, sizeof(uint))); offset += sizeof(uint); securityDescriptor.OffsetSacl = TypeMarshal.ToStruct<uint>( ArrayUtility.SubArray(buffer, offset, sizeof(uint))); offset += sizeof(uint); securityDescriptor.OffsetDacl = TypeMarshal.ToStruct<uint>( ArrayUtility.SubArray(buffer, offset, sizeof(uint))); offset += sizeof(uint); if (securityDescriptor.OffsetOwner != 0) { byte subAuthorityCount = buffer[securityDescriptor.OffsetOwner + sizeof(byte)]; //Size of Revision,SubAuthorityCount, IdentifierAuthority and SubAuthority. int sizeOfSid = sizeof(byte) + sizeof(byte) + sizeof(byte) * 6 + sizeof(uint) * subAuthorityCount; securityDescriptor.OwnerSid = TypeMarshal.ToStruct<_SID>( ArrayUtility.SubArray(buffer, (int)securityDescriptor.OffsetOwner, sizeOfSid)); } if (securityDescriptor.OffsetGroup != 0) { byte subAuthorityCount = buffer[securityDescriptor.OffsetGroup + sizeof(byte)]; //Size of Revision,SubAuthorityCount, IdentifierAuthority and SubAuthority. int sizeOfSid = sizeof(byte) + sizeof(byte) + sizeof(byte) * 6 + sizeof(uint) * subAuthorityCount; securityDescriptor.GroupSid = TypeMarshal.ToStruct<_SID>( ArrayUtility.SubArray(buffer, (int)securityDescriptor.OffsetGroup, sizeOfSid)); } if (securityDescriptor.OffsetSacl != 0) { //Add offset of AclRevision and Sbz1. ushort aclSize = TypeMarshal.ToStruct<ushort>( ArrayUtility.SubArray(buffer, (int)(securityDescriptor.OffsetSacl + sizeof(byte) + sizeof(byte)), sizeof(ushort))); securityDescriptor.Sacl = DtypUtility.DecodeAcl( ArrayUtility.SubArray(buffer, (int)securityDescriptor.OffsetSacl, aclSize)); } if (securityDescriptor.OffsetDacl != 0) { //Add offset of AclRevision and Sbz1. ushort aclSize = TypeMarshal.ToStruct<ushort>( ArrayUtility.SubArray(buffer, (int)(securityDescriptor.OffsetDacl + sizeof(byte) + sizeof(byte)), sizeof(ushort))); securityDescriptor.Dacl = DtypUtility.DecodeAcl( ArrayUtility.SubArray(buffer, (int)securityDescriptor.OffsetDacl, aclSize)); } return securityDescriptor; }
/// <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; }