/// <summary>
 /// the constructor
 /// </summary>
 /// <param name="flags">the security descriptor control flag</param>
 /// <param name="owner">the owner sid</param>
 /// <param name="group">the group sid</param>
 /// <param name="sacl">the sacl</param>
 /// <param name="dacl">the dacl</param>
 public _RawSecurityDescriptor(SECURITY_DESCRIPTOR_Control flags,
                               _SID?owner,
                               _SID?group,
                               _RawAcl sacl,
                               _RawAcl dacl)
 {
     controlFlags = flags;
     ownerSid     = owner;
     groupSid     = group;
     this.sacl    = sacl;
     this.dacl    = dacl;
 }
        /// <summary>
        /// the constructor
        /// </summary>
        /// <param name="binary">the input binary</param>
        /// <param name="offset">the offset in the binary</param>
        public _RawSecurityDescriptor(byte[] binary, int offset)
        {
            if (binary == null)
            {
                throw new ArgumentNullException(nameof(binary));
            }

            if (offset < 0 || offset > binary.Length - 0x14)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            controlFlags = (SECURITY_DESCRIPTOR_Control)BitConverter.ToUInt16(binary, offset + 2);

            //Get owner sid
            int ownerStart = BitConverter.ToInt32(binary, offset + 4);

            if (ownerStart != 0)
            {
                ownerSid = new _SID(binary, ownerStart);
            }

            //Get group sid
            int groupStart = BitConverter.ToInt32(binary, offset + 8);

            if (groupStart != 0)
            {
                groupSid = new _SID(binary, groupStart);
            }

            //Get sacl
            int saclStart = BitConverter.ToInt32(binary, offset + 12);

            if (saclStart != 0)
            {
                sacl = new _RawAcl(binary, saclStart);
            }

            //Get dacl
            int daclStart = BitConverter.ToInt32(binary, offset + 16);

            if (daclStart != 0)
            {
                dacl = new _RawAcl(binary, daclStart);
            }
        }
        public string GetSddlForm(SECURITY_DESCRIPTOR_Control flags, bool isDacl)
        {
            StringBuilder result = new StringBuilder();

            if (isDacl)
            {
                if (flags.HasFlag(SECURITY_DESCRIPTOR_Control.DACLProtected))
                {
                    result.Append("P");
                }
                if (flags.HasFlag(SECURITY_DESCRIPTOR_Control.DACLInheritanceRequired))
                {
                    result.Append("AR");
                }
                if (flags.HasFlag(SECURITY_DESCRIPTOR_Control.DACLAutoInherited))
                {
                    result.Append("AI");
                }
            }
            else
            {
                if (flags.HasFlag(SECURITY_DESCRIPTOR_Control.SACLProtected))
                {
                    result.Append("P");
                }
                if (flags.HasFlag(SECURITY_DESCRIPTOR_Control.SACLInheritanceRequired))
                {
                    result.Append("AR");
                }
                if (flags.HasFlag(SECURITY_DESCRIPTOR_Control.SACLAutoInherited))
                {
                    result.Append("AI");
                }
            }

            foreach (var ace in list)
            {
                result.Append(ace.GetSddlForm());
            }

            return(result.ToString());
        }
        /// <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>
        /// 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;
        }
        /// <summary>
        /// Create the binary from the buffer
        /// </summary>
        /// <param name="binary">The input binary</param>
        /// <param name="offset">The offset in the binary</param>
        public void GetBinaryForm(byte[] binary, int offset)
        {
            if (binary == null)
            {
                throw new ArgumentNullException(nameof(binary));
            }

            int binaryLength = Size;

            if (offset < 0 || offset > binary.Length - binaryLength)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            SECURITY_DESCRIPTOR_Control controlFlags = this.controlFlags;

            binary[offset]     = 1; //revision
            binary[offset + 1] = 0; //Sbz1
            DtypUtility.WriteUInt16ToByteArray((ushort)controlFlags, binary, offset + 2);

            int pointer = DtypUtility.SECURITY_DESCRIPTOR_FIXED_LENGTH;

            if (Owner != null)
            {
                DtypUtility.WriteInt32ToByteArray(pointer, binary, offset + 4);
                Owner.Value.GetBinaryForm(binary, offset + pointer);
                pointer += Owner.Value.Size;
            }
            else
            {
                DtypUtility.WriteInt32ToByteArray(0, binary, offset + 4);
            }

            if (Group != null)
            {
                DtypUtility.WriteInt32ToByteArray(pointer, binary, offset + 8);
                Group.Value.GetBinaryForm(binary, offset + pointer);
                pointer += Group.Value.Size;
            }
            else
            {
                DtypUtility.WriteInt32ToByteArray(0, binary, offset + 8);
            }

            _RawAcl sacl = this.SACL;

            if (this.controlFlags.HasFlag(SECURITY_DESCRIPTOR_Control.SACLPresent))
            {
                DtypUtility.WriteInt32ToByteArray(pointer, binary, offset + 12);
                sacl.GetBinaryForm(binary, offset + pointer);
                pointer += this.SACL.Size;
            }
            else
            {
                DtypUtility.WriteInt32ToByteArray(0, binary, offset + 12);
            }

            _RawAcl dacl = this.DACL;

            if (this.controlFlags.HasFlag(SECURITY_DESCRIPTOR_Control.DACLPresent))
            {
                DtypUtility.WriteInt32ToByteArray(pointer, binary, offset + 16);
                dacl.GetBinaryForm(binary, offset + pointer);
                pointer += this.DACL.Size;
            }
            else
            {
                DtypUtility.WriteInt32ToByteArray(0, binary, offset + 16);
            }
        }
 public _RawSecurityDescriptor(string sddl)
 {
     this.controlFlags |= SECURITY_DESCRIPTOR_Control.SelfRelative;
 }