SecurityDescriptor.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / clr / src / BCL / System / Security / AccessControl / SecurityDescriptor.cs / 1 / SecurityDescriptor.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Classes:  Security Descriptor family of classes 
**
** 
===========================================================*/

using Microsoft.Win32;
using System; 
using System.Runtime.InteropServices;
using System.Security.Principal; 
using System.Globalization; 

namespace System.Security.AccessControl 
{
    [Flags]

    public enum ControlFlags 
    {
        None                                = 0x0000, 
        OwnerDefaulted                      = 0x0001, // set by RM only 
        GroupDefaulted                      = 0x0002, // set by RM only
        DiscretionaryAclPresent             = 0x0004, // set by RM or user, 'off' means DACL is null 
        DiscretionaryAclDefaulted           = 0x0008, // set by RM only
        SystemAclPresent                    = 0x0010, // same as DiscretionaryAclPresent
        SystemAclDefaulted                  = 0x0020, // sams as DiscretionaryAclDefaulted
        DiscretionaryAclUntrusted           = 0x0040, // ignore this one 
        ServerSecurity                      = 0x0080, // ignore this one
        DiscretionaryAclAutoInheritRequired = 0x0100, // ignore this one 
        SystemAclAutoInheritRequired        = 0x0200, // ignore this one 
        DiscretionaryAclAutoInherited       = 0x0400, // set by RM only
        SystemAclAutoInherited              = 0x0800, // set by RM only 
        DiscretionaryAclProtected           = 0x1000, // when set, RM will stop inheriting
        SystemAclProtected                  = 0x2000, // when set, RM will stop inheriting
        RMControlValid                      = 0x4000, // the reserved 8 bits have some meaning
        SelfRelative                        = 0x8000, // must always be on 
    }
 
 
    public abstract class GenericSecurityDescriptor
    { 
        #region Protected Members

        //
        // Pictorially the structure of a security descriptor is as follows: 
        //
        //       3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 
        //       1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 
        //      +---------------------------------------------------------------+
        //      |            Control            |Reserved1 (SBZ)|   Revision    | 
        //      +---------------------------------------------------------------+
        //      |                            Owner                              |
        //      +---------------------------------------------------------------+
        //      |                            Group                              | 
        //      +----------------------------------------------------------------+
        //      |                            Sacl                               | 
        //      +---------------------------------------------------------------+ 
        //      |                            Dacl                               |
        //      +----------------------------------------------------------------+ 
        //

        internal const int HeaderLength = 20;
        internal const int OwnerFoundAt = 4; 
        internal const int GroupFoundAt = 8;
        internal const int SaclFoundAt = 12; 
        internal const int DaclFoundAt = 16; 

        #endregion 

        #region Private Methods

        // 
        // Stores an integer in big-endian format into an array at a given offset
        // 
 
        private static void MarshalInt( byte[] binaryForm, int offset, int number )
        { 
            binaryForm[offset + 0] = ( byte )( number >> 0 );
            binaryForm[offset + 1] = ( byte )( number >> 8 );
            binaryForm[offset + 2] = ( byte )( number >> 16 );
            binaryForm[offset + 3] = ( byte )( number >> 24 ); 
        }
 
        // 
        // Retrieves an integer stored in big-endian format at a given offset in an array
        // 

        internal static int UnmarshalInt( byte[] binaryForm, int offset )
        {
            return (int)( 
                ( binaryForm[offset + 0] <<  0 ) +
                ( binaryForm[offset + 1] <<  8 ) + 
                ( binaryForm[offset + 2] << 16 ) + 
                ( binaryForm[offset + 3] << 24 ));
        } 

        #endregion

        #region Constructors 

        protected GenericSecurityDescriptor() 
        { } 

        #endregion 

        #region Protected Properties

        // 
        // Marshaling logic requires calling into the derived
        // class to obtain pointers to SACL and DACL 
        // 

        internal abstract GenericAcl GenericSacl { get; } 
        internal abstract GenericAcl GenericDacl { get; }
        private bool IsCraftedAefaDacl
        {
            get 
            {
            	return  (GenericDacl is DiscretionaryAcl) && (GenericDacl as DiscretionaryAcl).EveryOneFullAccessForNullDacl; 
            } 
        }
 
        #endregion

        #region Public Properties
 
        public static bool IsSddlConversionSupported()
        { 
            return Win32.IsSddlConversionSupported(); 
        }
 
        public static byte Revision
        {
            get { return 1; }
        } 

        // 
        // Allows retrieving and setting the control bits for this security descriptor 
        //
 
        public abstract ControlFlags ControlFlags { get; }

        //
        // Allows retrieving and setting the owner SID for this security descriptor 
        //
 
        public abstract SecurityIdentifier Owner { get; set; } 

        // 
        // Allows retrieving and setting the group SID for this security descriptor
        //

        public abstract SecurityIdentifier Group { get; set; } 

        // 
        // Retrieves the length of the binary representation 
        // of the security descriptor
        // 

        public int BinaryLength
        {
            get 
            {
                int result = HeaderLength; 
 
                if ( Owner != null )
                { 
                    result += Owner.BinaryLength;
                }

                if ( Group != null ) 
                {
                    result += Group.BinaryLength; 
                } 

                if (( ControlFlags & ControlFlags.SystemAclPresent ) != 0 && 
                    GenericSacl != null )
                {
                    result += GenericSacl.BinaryLength;
                } 

                if (( ControlFlags & ControlFlags.DiscretionaryAclPresent ) != 0 && 
                    GenericDacl != null && !IsCraftedAefaDacl) 
                {
                    result += GenericDacl.BinaryLength; 
                }

                return result;
            } 
        }
 
        #endregion 

        #region Public Methods 

        //
        // Converts the security descriptor to its SDDL form
        // 

        public string GetSddlForm( AccessControlSections includeSections ) 
        { 
            byte[] binaryForm = new byte[BinaryLength];
            string resultSddl; 
            int error;

            GetBinaryForm( binaryForm, 0 );
 
            SecurityInfos flags = 0;
 
            if (( includeSections & AccessControlSections.Owner ) != 0 ) 
            {
                flags |= SecurityInfos.Owner; 
            }

            if (( includeSections & AccessControlSections.Group ) != 0 )
            { 
                flags |= SecurityInfos.Group;
            } 
 
            if (( includeSections & AccessControlSections.Audit ) != 0 )
            { 
                flags |= SecurityInfos.SystemAcl;
            }

            if (( includeSections & AccessControlSections.Access ) != 0 ) 
            {
                flags |= SecurityInfos.DiscretionaryAcl; 
            } 

            error = Win32.ConvertSdToSddl( binaryForm, 1, flags, out resultSddl ); 

            if ( error == Win32Native.ERROR_INVALID_PARAMETER ||
                error == Win32Native.ERROR_UNKNOWN_REVISION )
            { 
                //
                // Indicates that the marshaling logic in GetBinaryForm is busted 
                // 

                BCLDebug.Assert( false, "binaryForm produced invalid output" ); 
                throw new InvalidOperationException();
            }
            else if ( error != Win32Native.ERROR_SUCCESS )
            { 
                BCLDebug.Assert( false, string.Format( CultureInfo.InvariantCulture, "Win32.ConvertSdToSddl returned {0}", error ));
                throw new InvalidOperationException(); 
            } 

            return resultSddl; 
        }

        //
        // Converts the security descriptor to its binary form 
        //
 
        public void GetBinaryForm( byte[] binaryForm, int offset ) 
        {
            // 
            // the offset will grow as we go for each additional field (owner, group,
            // acl, etc) being written. But for each of such fields, we must use the
            // original offset as passed in, not the growing offset
            // 

            int originalOffset = offset; 
 
            if ( binaryForm == null )
            { 
                throw new ArgumentNullException( "binaryForm" );
            }

            if ( offset < 0 ) 
            {
                throw new ArgumentOutOfRangeException("offset", 
                    Environment.GetResourceString( "ArgumentOutOfRange_NeedNonNegNum" )); 
            }
 
            if ( binaryForm.Length - offset < BinaryLength )
            {
                throw new ArgumentOutOfRangeException(
                    "binaryForm", 
                    Environment.GetResourceString( "ArgumentOutOfRange_ArrayTooSmall" ));
            } 
 
            //
            // Populate the header 
            //

            int length = BinaryLength;
 
            byte rmControl =
                (( this is RawSecurityDescriptor ) && 
                 (( ControlFlags & ControlFlags.RMControlValid ) != 0 )) ? (( this as RawSecurityDescriptor ).ResourceManagerControl ) : ( byte )0; 

            // if the DACL is our internally crafted NULL replacement, then let us turn off this control 
            int materializedControlFlags = ( int )ControlFlags;
            if (IsCraftedAefaDacl)
            {
                unchecked {materializedControlFlags &= ~((int)ControlFlags.DiscretionaryAclPresent);} 
            }
 
            binaryForm[offset + 0] = Revision; 
            binaryForm[offset + 1] = rmControl;
            binaryForm[offset + 2] = ( byte )(( int )materializedControlFlags >> 0 ); 
            binaryForm[offset + 3] = ( byte )(( int )materializedControlFlags >> 8 );

            //
            // Compute offsets at which owner, group, SACL and DACL are stored 
            //
 
            int ownerOffset, groupOffset, saclOffset, daclOffset; 

            ownerOffset = offset + OwnerFoundAt; 
            groupOffset = offset + GroupFoundAt;
            saclOffset = offset + SaclFoundAt;
            daclOffset = offset + DaclFoundAt;
 
            offset += HeaderLength;
 
            // 
            // Marhsal the Owner SID into place
            // 

            if ( Owner != null )
            {
                MarshalInt( binaryForm, ownerOffset, offset - originalOffset ); 
                Owner.GetBinaryForm( binaryForm, offset );
                offset += Owner.BinaryLength; 
            } 
            else
            { 
                //
                // If Owner SID is null, store 0 in the offset field
                //
 
                MarshalInt( binaryForm, ownerOffset, 0 );
            } 
 
            //
            // Marshal the Group SID into place 
            //

            if ( Group != null )
            { 
                MarshalInt( binaryForm, groupOffset, offset - originalOffset );
                Group.GetBinaryForm( binaryForm, offset ); 
                offset += Group.BinaryLength; 
            }
            else 
            {
                //
                // If Group SID is null, store 0 in the offset field
                // 

                MarshalInt( binaryForm, groupOffset, 0 ); 
            } 

            // 
            // Marshal the SACL into place, if present
            //

            if (( ControlFlags & ControlFlags.SystemAclPresent ) != 0 && 
                GenericSacl != null )
            { 
                MarshalInt( binaryForm, saclOffset, offset - originalOffset ); 
                GenericSacl.GetBinaryForm( binaryForm, offset );
                offset += GenericSacl.BinaryLength; 
            }
            else
            {
                // 
                // If SACL is null or not present, store 0 in the offset field
                // 
 
                MarshalInt( binaryForm, saclOffset, 0 );
            } 

            //
            // Marshal the DACL into place, if present
            // 

            if (( ControlFlags & ControlFlags.DiscretionaryAclPresent ) != 0 && 
                GenericDacl != null && !IsCraftedAefaDacl ) 
            {
                MarshalInt( binaryForm, daclOffset, offset - originalOffset ); 
                GenericDacl.GetBinaryForm( binaryForm, offset );
                offset += GenericDacl.BinaryLength;
            }
            else 
            {
                // 
                // If DACL is null or not present, store 0 in the offset field 
                //
 
                MarshalInt( binaryForm, daclOffset, 0 );
            }
        }
 
        #endregion
    } 
 

    public sealed class RawSecurityDescriptor : GenericSecurityDescriptor 
    {
        #region Private Members

        private SecurityIdentifier _owner; 
        private SecurityIdentifier _group;
        private ControlFlags _flags; 
        private RawAcl _sacl; 
        private RawAcl _dacl;
        private byte _rmControl; // the not-so-reserved SBZ1 field 

        #endregion

        #region Protected Properties 

        internal override GenericAcl GenericSacl 
        { 
            get { return _sacl; }
        } 

        internal override GenericAcl GenericDacl
        {
            get { return _dacl; } 
        }
 
        #endregion 

        #region Private methods 

        private void CreateFromParts( ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, RawAcl systemAcl, RawAcl discretionaryAcl )
        {
            SetFlags( flags ); 
            Owner = owner;
            Group = group; 
            SystemAcl = systemAcl; 
            DiscretionaryAcl = discretionaryAcl;
            ResourceManagerControl = 0; 
        }

        #endregion
 
        #region Constructors
 
        // 
        // Creates a security descriptor explicitly
        // 

        public RawSecurityDescriptor( ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, RawAcl systemAcl, RawAcl discretionaryAcl )
            : base()
        { 
            CreateFromParts( flags, owner, group, systemAcl, discretionaryAcl );
        } 
 
        //
        // Creates a security descriptor from an SDDL string 
        //

        public RawSecurityDescriptor( string sddlForm )
            : this( BinaryFormFromSddlForm( sddlForm ), 0 ) 
        {
        } 
 
        //
        // Creates a security descriptor from its binary representation 
        // Important: the representation must be in self-relative format
        //

        public RawSecurityDescriptor( byte[] binaryForm, int offset ) 
            : base()
        { 
            ControlFlags flags; 
            SecurityIdentifier owner, group;
            RawAcl sacl, dacl; 
            byte rmControl;

            //
            // The array passed in must be valid 
            //
 
            if ( binaryForm == null ) 
            {
                throw new ArgumentNullException( "binaryForm" ); 
            }

            if ( offset < 0 )
            { 
                //
                // Offset must not be negative 
                // 

                throw new ArgumentOutOfRangeException("offset", 
                    Environment.GetResourceString( "ArgumentOutOfRange_NeedNonNegNum" ));
            }

            // 
            // At least make sure the header is in place
            // 
 
            if ( binaryForm.Length - offset < HeaderLength )
            { 
                throw new ArgumentOutOfRangeException(
                    "binaryForm",
                    Environment.GetResourceString( "ArgumentOutOfRange_ArrayTooSmall" ));
            } 

            // 
            // We only understand revision-1 security descriptors 
            //
 
            if ( binaryForm[offset + 0] != Revision )
            {
                throw new ArgumentOutOfRangeException("binaryForm",
                    Environment.GetResourceString( "AccessControl_InvalidSecurityDescriptorRevision" )); 
            }
 
            // 
            // Extract the ResourceManagerControl field
            // 

            rmControl = binaryForm[offset + 1];

            // 
            // Extract the control flags
            // 
 
            flags = ( ControlFlags )(( binaryForm[offset + 2] << 0 ) + ( binaryForm[offset + 3] << 8 ));
 
            //
            // Make sure that the input is in self-relative format
            //
 
            if (( flags & ControlFlags.SelfRelative ) == 0 )
            { 
                throw new ArgumentException( 
                    Environment.GetResourceString( "AccessControl_InvalidSecurityDescriptorSelfRelativeForm" ),
                    "binaryForm" ); 
            }

            //
            // Extract the owner SID 
            //
 
            int ownerOffset = UnmarshalInt( binaryForm, offset + OwnerFoundAt ); 

            if ( ownerOffset != 0 ) 
            {
                owner = new SecurityIdentifier( binaryForm, offset + ownerOffset );
            }
            else 
            {
                owner = null; 
            } 

            // 
            // Extract the group SID
            //

            int groupOffset = UnmarshalInt( binaryForm, offset + GroupFoundAt ); 

            if ( groupOffset != 0 ) 
            { 
                group = new SecurityIdentifier( binaryForm, offset + groupOffset );
            } 
            else
            {
                group = null;
            } 

            // 
            // Extract the SACL 
            //
 
            int saclOffset = UnmarshalInt( binaryForm, offset + SaclFoundAt );

            if ((( flags & ControlFlags.SystemAclPresent ) != 0 ) &&
                saclOffset != 0 ) 
            {
                sacl = new RawAcl( binaryForm, offset + saclOffset ); 
            } 
            else
            { 
                sacl = null;
            }

            // 
            // Extract the DACL
            // 
 
            int daclOffset = UnmarshalInt( binaryForm, offset + DaclFoundAt );
 
            if ((( flags & ControlFlags.DiscretionaryAclPresent ) != 0 ) &&
                daclOffset != 0 )
            {
                dacl = new RawAcl( binaryForm, offset + daclOffset ); 
            }
            else 
            { 
                dacl = null;
            } 

            //
            // Create the resulting security descriptor
            // 

            CreateFromParts( flags, owner, group, sacl, dacl ); 
 
            //
            // In the offchance that the flags indicate that the rmControl 
            // field is meaningful, remember what was there.
            //

            if (( flags & ControlFlags.RMControlValid ) != 0 ) 
            {
                ResourceManagerControl = rmControl; 
            } 
        }
 
        #endregion

        #region Static Methods
 
        private static byte[] BinaryFormFromSddlForm( string sddlForm )
        { 
            if ( !IsSddlConversionSupported()) 
            {
                throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_Win9x" )); 
            }

            if ( sddlForm == null )
            { 
                throw new ArgumentNullException( "sddlForm" );
            } 
 
            int error;
            IntPtr byteArray = IntPtr.Zero; 
            uint byteArraySize = 0;
            const System.Int32 TRUE = 1;
            byte[] binaryForm = null;
 
            try
            { 
                if ( TRUE != Win32Native.ConvertStringSdToSd( 
                        sddlForm,
                        GenericSecurityDescriptor.Revision, 
                        out byteArray,
                        ref byteArraySize ))
                {
                    error = Marshal.GetLastWin32Error(); 

                    if ( error == Win32Native.ERROR_INVALID_PARAMETER || 
                        error == Win32Native.ERROR_INVALID_ACL || 
                        error == Win32Native.ERROR_INVALID_SECURITY_DESCR ||
                        error == Win32Native.ERROR_UNKNOWN_REVISION ) 
                    {
                        throw new ArgumentException(
                            Environment.GetResourceString( "ArgumentException_InvalidSDSddlForm" ),
                            "sddlForm" ); 
                    }
                    else if ( error == Win32Native.ERROR_NOT_ENOUGH_MEMORY ) 
                    { 
                        throw new OutOfMemoryException();
                    } 
                    else if ( error == Win32Native.ERROR_INVALID_SID )
                    {
                        throw new ArgumentException(
                            Environment.GetResourceString( "AccessControl_InvalidSidInSDDLString" ), 
                            "sddlForm" );
                    } 
                    else if ( error != Win32Native.ERROR_SUCCESS ) 
                    {
                        BCLDebug.Assert( false, string.Format( CultureInfo.InvariantCulture, "Unexpected error out of Win32.ConvertStringSdToSd: {0}", error )); 
                        throw new SystemException();
                    }
                }
 
                binaryForm = new byte[byteArraySize];
 
                // 
                // Extract the data from the returned pointer
                // 

                Marshal.Copy( byteArray, binaryForm, 0, ( int )byteArraySize );
            }
            finally 
            {
                // 
                // Now is a good time to get rid of the returned pointer 
                //
                if (byteArray != IntPtr.Zero) 
                {
                    Win32Native.LocalFree( byteArray );
                }
            } 

            return binaryForm; 
        } 

        #endregion 

        #region Public Properties

        // 
        // Allows retrieving the control bits for this security descriptor
        // Important: Special checks must be applied when setting flags and not 
        // all flags can be set (for instance, we only deal with self-relative 
        // security descriptors), thus flags can be set through other methods.
        // 

        public override ControlFlags ControlFlags
        {
            get 
            {
                return _flags; 
            } 
        }
 
        //
        // Allows retrieving and setting the owner SID for this security descriptor
        //
 
        public override SecurityIdentifier Owner
        { 
            get 
            {
                return _owner; 
            }

            set
            { 
                _owner = value;
            } 
        } 

        // 
        // Allows retrieving and setting the group SID for this security descriptor
        //

        public override SecurityIdentifier Group 
        {
            get 
            { 
                return _group;
            } 

            set
            {
                _group = value; 
            }
        } 
 
        //
        // Allows retrieving and setting the SACL for this security descriptor 
        //

        public RawAcl SystemAcl
        { 
            get
            { 
                return _sacl; 
            }
 
            set
            {
                _sacl = value;
            } 
        }
 
        // 
        // Allows retrieving and setting the DACL for this security descriptor
        // 

        public RawAcl DiscretionaryAcl
        {
            get 
            {
                return _dacl; 
            } 

            set 
            {
                _dacl = value;
            }
        } 

        // 
        // CORNER CASE (LEGACY) 
        // The ostensibly "reserved" field in the Security Descriptor header
        // can in fact be used by obscure resource managers which in this 
        // case must set the RMControlValid flag.
        //

        public byte ResourceManagerControl 
        {
            get 
            { 
                return _rmControl;
            } 

            set
            {
                _rmControl = value; 
            }
        } 
 

        #endregion 

        #region Public Methods

        public void SetFlags( ControlFlags flags ) 
        {
            // 
            // We can not deal with non-self-relative descriptors 
            // so just forget about it
            // 

            _flags = ( flags | ControlFlags.SelfRelative );
        }
 
        #endregion
    } 
 

    public sealed class CommonSecurityDescriptor : GenericSecurityDescriptor 
    {
        #region Private Members

        bool _isContainer; 
        bool _isDS;
        private RawSecurityDescriptor _rawSd; 
        private SystemAcl _sacl; 
        private DiscretionaryAcl _dacl;
 

        #endregion

        #region Private Methods 

        private void CreateFromParts( bool isContainer, bool isDS, ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, SystemAcl systemAcl, DiscretionaryAcl discretionaryAcl ) 
        { 
            if ( systemAcl != null &&
                systemAcl.IsContainer != isContainer ) 
            {
                throw new ArgumentException(
                    Environment.GetResourceString( isContainer ?
                        "AccessControl_MustSpecifyContainerAcl" : 
                        "AccessControl_MustSpecifyLeafObjectAcl" ),
                    "systemAcl" ); 
            } 

            if ( discretionaryAcl != null && 
                discretionaryAcl.IsContainer != isContainer )
            {
                throw new ArgumentException(
                    Environment.GetResourceString( isContainer ? 
                        "AccessControl_MustSpecifyContainerAcl" :
                        "AccessControl_MustSpecifyLeafObjectAcl" ), 
                    "discretionaryAcl" ); 
            }
 
            _isContainer = isContainer;

            if ( systemAcl != null &&
                systemAcl.IsDS != isDS ) 
            {
                throw new ArgumentException( 
                    Environment.GetResourceString( isDS ? 
                        "AccessControl_MustSpecifyDirectoryObjectAcl" :
                        "AccessControl_MustSpecifyNonDirectoryObjectAcl"), 
                    "systemAcl");
            }

            if ( discretionaryAcl != null && 
                discretionaryAcl.IsDS != isDS )
            { 
                throw new ArgumentException( 
                    Environment.GetResourceString( isDS ?
                        "AccessControl_MustSpecifyDirectoryObjectAcl" : 
                        "AccessControl_MustSpecifyNonDirectoryObjectAcl"),
                    "discretionaryAcl");
            }
 
            _isDS = isDS;
 
            _sacl = systemAcl; 

            // 
            // Replace null DACL with an allow-all for everyone DACL
            //

            if ( discretionaryAcl == null ) 
            {
                // 
                // to conform to native behavior, we will add allow everyone ace for DACL 
                //
 
                discretionaryAcl = DiscretionaryAcl.CreateAllowEveryoneFullAccess(_isDS, _isContainer);
            }

            _dacl = discretionaryAcl; 

            // 
            // DACL is never null. So always set the flag bit on 
            //
 
            ControlFlags actualFlags = flags | ControlFlags.DiscretionaryAclPresent;

            //
            // Keep SACL and the flag bit in [....]. 
            //
 
            if (systemAcl == null) 
            {
                unchecked { actualFlags &= ~(ControlFlags.SystemAclPresent); } 
            }
            else
            {
                actualFlags |= (ControlFlags.SystemAclPresent); 
            }
 
            _rawSd = new RawSecurityDescriptor( actualFlags, owner, group, systemAcl == null ? null : systemAcl.RawAcl, discretionaryAcl.RawAcl ); 
        }
 
        #endregion

        #region Constructors
 
        //
        // Creates a security descriptor explicitly 
        // 

        public CommonSecurityDescriptor( bool isContainer, bool isDS, ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, SystemAcl systemAcl, DiscretionaryAcl discretionaryAcl ) 
        {
            CreateFromParts( isContainer, isDS, flags, owner, group, systemAcl, discretionaryAcl );
        }
 
        private CommonSecurityDescriptor( bool isContainer, bool isDS, ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, RawAcl systemAcl, RawAcl discretionaryAcl )
            : this( isContainer, isDS, flags, owner, group, systemAcl == null ? null : new SystemAcl( isContainer, isDS, systemAcl ), discretionaryAcl == null ? null : new DiscretionaryAcl( isContainer, isDS, discretionaryAcl )) 
        { 
        }
 
        public CommonSecurityDescriptor( bool isContainer, bool isDS, RawSecurityDescriptor rawSecurityDescriptor )
            : this( isContainer, isDS, rawSecurityDescriptor, false )
        {
        } 

        internal CommonSecurityDescriptor( bool isContainer, bool isDS, RawSecurityDescriptor rawSecurityDescriptor, bool trusted ) 
        { 
            if ( rawSecurityDescriptor == null )
            { 
                throw new ArgumentNullException( "rawSecurityDescriptor" );
            }

            CreateFromParts( 
                isContainer,
                isDS, 
                rawSecurityDescriptor.ControlFlags, 
                rawSecurityDescriptor.Owner,
                rawSecurityDescriptor.Group, 
                rawSecurityDescriptor.SystemAcl == null ? null : new SystemAcl( isContainer, isDS, rawSecurityDescriptor.SystemAcl, trusted ),
                rawSecurityDescriptor.DiscretionaryAcl == null ? null : new DiscretionaryAcl( isContainer, isDS, rawSecurityDescriptor.DiscretionaryAcl, trusted ));
        }
 
        //
        // Create a security descriptor from an SDDL string 
        // 

        public CommonSecurityDescriptor( bool isContainer, bool isDS, string sddlForm ) 
            : this( isContainer, isDS, new RawSecurityDescriptor( sddlForm ), true )
        {
        }
 
        //
        // Create a security descriptor from its binary representation 
        // 

        public CommonSecurityDescriptor( bool isContainer, bool isDS, byte[] binaryForm, int offset ) 
            : this( isContainer, isDS, new RawSecurityDescriptor( binaryForm, offset ), true )
        {
        }
 
        #endregion
 
        #region Protected Properties 

        internal sealed override GenericAcl GenericSacl 
        {
            get { return _sacl; }
        }
 
        internal sealed override GenericAcl GenericDacl
        { 
            get { return _dacl; } 
        }
 
        #endregion

        #region Public Properties
 
        public bool IsContainer
        { 
            get { return _isContainer; } 
        }
 
        public bool IsDS
        {
            get { return _isDS; }
        } 

 
        // 
        // Allows retrieving the control bits for this security descriptor
        // 

        public override ControlFlags ControlFlags
        {
            get 
            {
                return _rawSd.ControlFlags; 
            } 
        }
 
        //
        // Allows retrieving and setting the owner SID for this security descriptor
        //
 
        public override SecurityIdentifier Owner
        { 
            get 
            {
                return _rawSd.Owner; 
            }

            set
            { 
                _rawSd.Owner = value;
            } 
        } 

        // 
        // Allows retrieving and setting the group SID for this security descriptor
        //

        public override SecurityIdentifier Group 
        {
            get 
            { 
                return _rawSd.Group;
            } 

            set
            {
                _rawSd.Group = value; 
            }
        } 
 

        public SystemAcl SystemAcl 
        {
            get
            {
                return _sacl; 
            }
 
            set 
            {
                if ( value != null ) 
                {
                    if ( value.IsContainer != this.IsContainer )
                    {
                        throw new ArgumentException( 
                            Environment.GetResourceString( this.IsContainer ?
                                "AccessControl_MustSpecifyContainerAcl" : 
                                "AccessControl_MustSpecifyLeafObjectAcl" ), 
                            "value" );
                    } 

                    if ( value.IsDS != this.IsDS )
                    {
                        throw new ArgumentException( 
                            Environment.GetResourceString(this.IsDS ?
                                "AccessControl_MustSpecifyDirectoryObjectAcl" : 
                                "AccessControl_MustSpecifyNonDirectoryObjectAcl"), 
                            "value");
                    } 
                }

                _sacl = value;
 
                if ( _sacl != null )
                { 
                    _rawSd.SystemAcl = _sacl.RawAcl; 
                    AddControlFlags( ControlFlags.SystemAclPresent );
                } 
                else
                {
                    _rawSd.SystemAcl = null;
                    RemoveControlFlags( ControlFlags.SystemAclPresent ); 
                }
            } 
        } 

        // 
        // Allows retrieving and setting the DACL for this security descriptor
        //

        public DiscretionaryAcl DiscretionaryAcl 
        {
            get 
            { 
                return _dacl;
            } 

            set
            {
                if ( value != null ) 
                {
                    if ( value.IsContainer != this.IsContainer ) 
                    { 
                        throw new ArgumentException(
                            Environment.GetResourceString( this.IsContainer ? 
                                "AccessControl_MustSpecifyContainerAcl" :
                                "AccessControl_MustSpecifyLeafObjectAcl" ),
                            "value" );
                    } 

                    if ( value.IsDS != this.IsDS ) 
                    { 
                        throw new ArgumentException(
                            Environment.GetResourceString( this.IsDS ? 
                                "AccessControl_MustSpecifyDirectoryObjectAcl" :
                                "AccessControl_MustSpecifyNonDirectoryObjectAcl"),
                            "value");
                    } 
                }
 
                // 
                // NULL DACLs are replaced with allow everyone full access DACLs.
                // 

                if ( value == null )
                {
                    _dacl = DiscretionaryAcl.CreateAllowEveryoneFullAccess(IsDS, IsContainer); 
                }
                else 
                { 
                    _dacl = value;
                } 

                _rawSd.DiscretionaryAcl = _dacl.RawAcl;
                AddControlFlags( ControlFlags.DiscretionaryAclPresent );
            } 
        }
 
        public bool IsSystemAclCanonical 
        {
            get { return ( SystemAcl == null || SystemAcl.IsCanonical ); } 
        }

        public bool IsDiscretionaryAclCanonical
        { 
            get { return ( DiscretionaryAcl == null || DiscretionaryAcl.IsCanonical ); }
        } 
 
        #endregion
 
        #region Public Methods

        public void SetSystemAclProtection( bool isProtected, bool preserveInheritance )
        { 
            if ( !isProtected )
            { 
                RemoveControlFlags( ControlFlags.SystemAclProtected ); 
            }
            else 
            {
                if ( !preserveInheritance && SystemAcl != null )
                {
                    SystemAcl.RemoveInheritedAces(); 
                }
 
                AddControlFlags( ControlFlags.SystemAclProtected ); 
            }
        } 

        public void SetDiscretionaryAclProtection( bool isProtected, bool preserveInheritance )
        {
            if ( !isProtected ) 
            {
                RemoveControlFlags( ControlFlags.DiscretionaryAclProtected ); 
            } 
            else
            { 
                if ( !preserveInheritance && DiscretionaryAcl != null )
                {
                    DiscretionaryAcl.RemoveInheritedAces();
                } 

                AddControlFlags( ControlFlags.DiscretionaryAclProtected ); 
            } 
            if (DiscretionaryAcl != null && DiscretionaryAcl.EveryOneFullAccessForNullDacl)
            { 
                DiscretionaryAcl.EveryOneFullAccessForNullDacl = false;
            }
        }
 
        public void PurgeAccessControl( SecurityIdentifier sid )
        { 
            if ( sid == null ) 
            {
                throw new ArgumentNullException( "sid" ); 
            }

            if ( DiscretionaryAcl != null )
            { 
                DiscretionaryAcl.Purge( sid );
            } 
        } 

        public void PurgeAudit( SecurityIdentifier sid ) 
        {
            if ( sid == null )
            {
                throw new ArgumentNullException( "sid" ); 
            }
 
            if ( SystemAcl != null ) 
            {
                SystemAcl.Purge( sid ); 
            }
        }

        #endregion 

        #region internal Methods 
        internal void UpdateControlFlags(ControlFlags flagsToUpdate, ControlFlags newFlags) 
        {
            ControlFlags finalFlags = newFlags | (_rawSd.ControlFlags & (~flagsToUpdate)); 
            _rawSd.SetFlags(finalFlags);
        }

        // 
        // These two add/remove method must be called with great care (and thus it is internal)
        // The caller is responsible for keeping the SaclPresent and DaclPresent bits in [....] 
        // with the actual SACL and DACL. 
        //
 
        internal void AddControlFlags(ControlFlags flags)
        {
            _rawSd.SetFlags(_rawSd.ControlFlags | flags);
        } 

        internal void RemoveControlFlags(ControlFlags flags) 
        { 
            unchecked
            { 
                _rawSd.SetFlags(_rawSd.ControlFlags & ~flags);
            }
        }
 
        internal bool IsSystemAclPresent
        { 
            get 
            {
                return (_rawSd.ControlFlags & ControlFlags.SystemAclPresent) != 0; 
            }
        }

        internal bool IsDiscretionaryAclPresent 
        {
            get 
            { 
                return (_rawSd.ControlFlags & ControlFlags.DiscretionaryAclPresent) != 0;
            } 
        }
        #endregion
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Classes:  Security Descriptor family of classes 
**
** 
===========================================================*/

using Microsoft.Win32;
using System; 
using System.Runtime.InteropServices;
using System.Security.Principal; 
using System.Globalization; 

namespace System.Security.AccessControl 
{
    [Flags]

    public enum ControlFlags 
    {
        None                                = 0x0000, 
        OwnerDefaulted                      = 0x0001, // set by RM only 
        GroupDefaulted                      = 0x0002, // set by RM only
        DiscretionaryAclPresent             = 0x0004, // set by RM or user, 'off' means DACL is null 
        DiscretionaryAclDefaulted           = 0x0008, // set by RM only
        SystemAclPresent                    = 0x0010, // same as DiscretionaryAclPresent
        SystemAclDefaulted                  = 0x0020, // sams as DiscretionaryAclDefaulted
        DiscretionaryAclUntrusted           = 0x0040, // ignore this one 
        ServerSecurity                      = 0x0080, // ignore this one
        DiscretionaryAclAutoInheritRequired = 0x0100, // ignore this one 
        SystemAclAutoInheritRequired        = 0x0200, // ignore this one 
        DiscretionaryAclAutoInherited       = 0x0400, // set by RM only
        SystemAclAutoInherited              = 0x0800, // set by RM only 
        DiscretionaryAclProtected           = 0x1000, // when set, RM will stop inheriting
        SystemAclProtected                  = 0x2000, // when set, RM will stop inheriting
        RMControlValid                      = 0x4000, // the reserved 8 bits have some meaning
        SelfRelative                        = 0x8000, // must always be on 
    }
 
 
    public abstract class GenericSecurityDescriptor
    { 
        #region Protected Members

        //
        // Pictorially the structure of a security descriptor is as follows: 
        //
        //       3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 
        //       1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 
        //      +---------------------------------------------------------------+
        //      |            Control            |Reserved1 (SBZ)|   Revision    | 
        //      +---------------------------------------------------------------+
        //      |                            Owner                              |
        //      +---------------------------------------------------------------+
        //      |                            Group                              | 
        //      +----------------------------------------------------------------+
        //      |                            Sacl                               | 
        //      +---------------------------------------------------------------+ 
        //      |                            Dacl                               |
        //      +----------------------------------------------------------------+ 
        //

        internal const int HeaderLength = 20;
        internal const int OwnerFoundAt = 4; 
        internal const int GroupFoundAt = 8;
        internal const int SaclFoundAt = 12; 
        internal const int DaclFoundAt = 16; 

        #endregion 

        #region Private Methods

        // 
        // Stores an integer in big-endian format into an array at a given offset
        // 
 
        private static void MarshalInt( byte[] binaryForm, int offset, int number )
        { 
            binaryForm[offset + 0] = ( byte )( number >> 0 );
            binaryForm[offset + 1] = ( byte )( number >> 8 );
            binaryForm[offset + 2] = ( byte )( number >> 16 );
            binaryForm[offset + 3] = ( byte )( number >> 24 ); 
        }
 
        // 
        // Retrieves an integer stored in big-endian format at a given offset in an array
        // 

        internal static int UnmarshalInt( byte[] binaryForm, int offset )
        {
            return (int)( 
                ( binaryForm[offset + 0] <<  0 ) +
                ( binaryForm[offset + 1] <<  8 ) + 
                ( binaryForm[offset + 2] << 16 ) + 
                ( binaryForm[offset + 3] << 24 ));
        } 

        #endregion

        #region Constructors 

        protected GenericSecurityDescriptor() 
        { } 

        #endregion 

        #region Protected Properties

        // 
        // Marshaling logic requires calling into the derived
        // class to obtain pointers to SACL and DACL 
        // 

        internal abstract GenericAcl GenericSacl { get; } 
        internal abstract GenericAcl GenericDacl { get; }
        private bool IsCraftedAefaDacl
        {
            get 
            {
            	return  (GenericDacl is DiscretionaryAcl) && (GenericDacl as DiscretionaryAcl).EveryOneFullAccessForNullDacl; 
            } 
        }
 
        #endregion

        #region Public Properties
 
        public static bool IsSddlConversionSupported()
        { 
            return Win32.IsSddlConversionSupported(); 
        }
 
        public static byte Revision
        {
            get { return 1; }
        } 

        // 
        // Allows retrieving and setting the control bits for this security descriptor 
        //
 
        public abstract ControlFlags ControlFlags { get; }

        //
        // Allows retrieving and setting the owner SID for this security descriptor 
        //
 
        public abstract SecurityIdentifier Owner { get; set; } 

        // 
        // Allows retrieving and setting the group SID for this security descriptor
        //

        public abstract SecurityIdentifier Group { get; set; } 

        // 
        // Retrieves the length of the binary representation 
        // of the security descriptor
        // 

        public int BinaryLength
        {
            get 
            {
                int result = HeaderLength; 
 
                if ( Owner != null )
                { 
                    result += Owner.BinaryLength;
                }

                if ( Group != null ) 
                {
                    result += Group.BinaryLength; 
                } 

                if (( ControlFlags & ControlFlags.SystemAclPresent ) != 0 && 
                    GenericSacl != null )
                {
                    result += GenericSacl.BinaryLength;
                } 

                if (( ControlFlags & ControlFlags.DiscretionaryAclPresent ) != 0 && 
                    GenericDacl != null && !IsCraftedAefaDacl) 
                {
                    result += GenericDacl.BinaryLength; 
                }

                return result;
            } 
        }
 
        #endregion 

        #region Public Methods 

        //
        // Converts the security descriptor to its SDDL form
        // 

        public string GetSddlForm( AccessControlSections includeSections ) 
        { 
            byte[] binaryForm = new byte[BinaryLength];
            string resultSddl; 
            int error;

            GetBinaryForm( binaryForm, 0 );
 
            SecurityInfos flags = 0;
 
            if (( includeSections & AccessControlSections.Owner ) != 0 ) 
            {
                flags |= SecurityInfos.Owner; 
            }

            if (( includeSections & AccessControlSections.Group ) != 0 )
            { 
                flags |= SecurityInfos.Group;
            } 
 
            if (( includeSections & AccessControlSections.Audit ) != 0 )
            { 
                flags |= SecurityInfos.SystemAcl;
            }

            if (( includeSections & AccessControlSections.Access ) != 0 ) 
            {
                flags |= SecurityInfos.DiscretionaryAcl; 
            } 

            error = Win32.ConvertSdToSddl( binaryForm, 1, flags, out resultSddl ); 

            if ( error == Win32Native.ERROR_INVALID_PARAMETER ||
                error == Win32Native.ERROR_UNKNOWN_REVISION )
            { 
                //
                // Indicates that the marshaling logic in GetBinaryForm is busted 
                // 

                BCLDebug.Assert( false, "binaryForm produced invalid output" ); 
                throw new InvalidOperationException();
            }
            else if ( error != Win32Native.ERROR_SUCCESS )
            { 
                BCLDebug.Assert( false, string.Format( CultureInfo.InvariantCulture, "Win32.ConvertSdToSddl returned {0}", error ));
                throw new InvalidOperationException(); 
            } 

            return resultSddl; 
        }

        //
        // Converts the security descriptor to its binary form 
        //
 
        public void GetBinaryForm( byte[] binaryForm, int offset ) 
        {
            // 
            // the offset will grow as we go for each additional field (owner, group,
            // acl, etc) being written. But for each of such fields, we must use the
            // original offset as passed in, not the growing offset
            // 

            int originalOffset = offset; 
 
            if ( binaryForm == null )
            { 
                throw new ArgumentNullException( "binaryForm" );
            }

            if ( offset < 0 ) 
            {
                throw new ArgumentOutOfRangeException("offset", 
                    Environment.GetResourceString( "ArgumentOutOfRange_NeedNonNegNum" )); 
            }
 
            if ( binaryForm.Length - offset < BinaryLength )
            {
                throw new ArgumentOutOfRangeException(
                    "binaryForm", 
                    Environment.GetResourceString( "ArgumentOutOfRange_ArrayTooSmall" ));
            } 
 
            //
            // Populate the header 
            //

            int length = BinaryLength;
 
            byte rmControl =
                (( this is RawSecurityDescriptor ) && 
                 (( ControlFlags & ControlFlags.RMControlValid ) != 0 )) ? (( this as RawSecurityDescriptor ).ResourceManagerControl ) : ( byte )0; 

            // if the DACL is our internally crafted NULL replacement, then let us turn off this control 
            int materializedControlFlags = ( int )ControlFlags;
            if (IsCraftedAefaDacl)
            {
                unchecked {materializedControlFlags &= ~((int)ControlFlags.DiscretionaryAclPresent);} 
            }
 
            binaryForm[offset + 0] = Revision; 
            binaryForm[offset + 1] = rmControl;
            binaryForm[offset + 2] = ( byte )(( int )materializedControlFlags >> 0 ); 
            binaryForm[offset + 3] = ( byte )(( int )materializedControlFlags >> 8 );

            //
            // Compute offsets at which owner, group, SACL and DACL are stored 
            //
 
            int ownerOffset, groupOffset, saclOffset, daclOffset; 

            ownerOffset = offset + OwnerFoundAt; 
            groupOffset = offset + GroupFoundAt;
            saclOffset = offset + SaclFoundAt;
            daclOffset = offset + DaclFoundAt;
 
            offset += HeaderLength;
 
            // 
            // Marhsal the Owner SID into place
            // 

            if ( Owner != null )
            {
                MarshalInt( binaryForm, ownerOffset, offset - originalOffset ); 
                Owner.GetBinaryForm( binaryForm, offset );
                offset += Owner.BinaryLength; 
            } 
            else
            { 
                //
                // If Owner SID is null, store 0 in the offset field
                //
 
                MarshalInt( binaryForm, ownerOffset, 0 );
            } 
 
            //
            // Marshal the Group SID into place 
            //

            if ( Group != null )
            { 
                MarshalInt( binaryForm, groupOffset, offset - originalOffset );
                Group.GetBinaryForm( binaryForm, offset ); 
                offset += Group.BinaryLength; 
            }
            else 
            {
                //
                // If Group SID is null, store 0 in the offset field
                // 

                MarshalInt( binaryForm, groupOffset, 0 ); 
            } 

            // 
            // Marshal the SACL into place, if present
            //

            if (( ControlFlags & ControlFlags.SystemAclPresent ) != 0 && 
                GenericSacl != null )
            { 
                MarshalInt( binaryForm, saclOffset, offset - originalOffset ); 
                GenericSacl.GetBinaryForm( binaryForm, offset );
                offset += GenericSacl.BinaryLength; 
            }
            else
            {
                // 
                // If SACL is null or not present, store 0 in the offset field
                // 
 
                MarshalInt( binaryForm, saclOffset, 0 );
            } 

            //
            // Marshal the DACL into place, if present
            // 

            if (( ControlFlags & ControlFlags.DiscretionaryAclPresent ) != 0 && 
                GenericDacl != null && !IsCraftedAefaDacl ) 
            {
                MarshalInt( binaryForm, daclOffset, offset - originalOffset ); 
                GenericDacl.GetBinaryForm( binaryForm, offset );
                offset += GenericDacl.BinaryLength;
            }
            else 
            {
                // 
                // If DACL is null or not present, store 0 in the offset field 
                //
 
                MarshalInt( binaryForm, daclOffset, 0 );
            }
        }
 
        #endregion
    } 
 

    public sealed class RawSecurityDescriptor : GenericSecurityDescriptor 
    {
        #region Private Members

        private SecurityIdentifier _owner; 
        private SecurityIdentifier _group;
        private ControlFlags _flags; 
        private RawAcl _sacl; 
        private RawAcl _dacl;
        private byte _rmControl; // the not-so-reserved SBZ1 field 

        #endregion

        #region Protected Properties 

        internal override GenericAcl GenericSacl 
        { 
            get { return _sacl; }
        } 

        internal override GenericAcl GenericDacl
        {
            get { return _dacl; } 
        }
 
        #endregion 

        #region Private methods 

        private void CreateFromParts( ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, RawAcl systemAcl, RawAcl discretionaryAcl )
        {
            SetFlags( flags ); 
            Owner = owner;
            Group = group; 
            SystemAcl = systemAcl; 
            DiscretionaryAcl = discretionaryAcl;
            ResourceManagerControl = 0; 
        }

        #endregion
 
        #region Constructors
 
        // 
        // Creates a security descriptor explicitly
        // 

        public RawSecurityDescriptor( ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, RawAcl systemAcl, RawAcl discretionaryAcl )
            : base()
        { 
            CreateFromParts( flags, owner, group, systemAcl, discretionaryAcl );
        } 
 
        //
        // Creates a security descriptor from an SDDL string 
        //

        public RawSecurityDescriptor( string sddlForm )
            : this( BinaryFormFromSddlForm( sddlForm ), 0 ) 
        {
        } 
 
        //
        // Creates a security descriptor from its binary representation 
        // Important: the representation must be in self-relative format
        //

        public RawSecurityDescriptor( byte[] binaryForm, int offset ) 
            : base()
        { 
            ControlFlags flags; 
            SecurityIdentifier owner, group;
            RawAcl sacl, dacl; 
            byte rmControl;

            //
            // The array passed in must be valid 
            //
 
            if ( binaryForm == null ) 
            {
                throw new ArgumentNullException( "binaryForm" ); 
            }

            if ( offset < 0 )
            { 
                //
                // Offset must not be negative 
                // 

                throw new ArgumentOutOfRangeException("offset", 
                    Environment.GetResourceString( "ArgumentOutOfRange_NeedNonNegNum" ));
            }

            // 
            // At least make sure the header is in place
            // 
 
            if ( binaryForm.Length - offset < HeaderLength )
            { 
                throw new ArgumentOutOfRangeException(
                    "binaryForm",
                    Environment.GetResourceString( "ArgumentOutOfRange_ArrayTooSmall" ));
            } 

            // 
            // We only understand revision-1 security descriptors 
            //
 
            if ( binaryForm[offset + 0] != Revision )
            {
                throw new ArgumentOutOfRangeException("binaryForm",
                    Environment.GetResourceString( "AccessControl_InvalidSecurityDescriptorRevision" )); 
            }
 
            // 
            // Extract the ResourceManagerControl field
            // 

            rmControl = binaryForm[offset + 1];

            // 
            // Extract the control flags
            // 
 
            flags = ( ControlFlags )(( binaryForm[offset + 2] << 0 ) + ( binaryForm[offset + 3] << 8 ));
 
            //
            // Make sure that the input is in self-relative format
            //
 
            if (( flags & ControlFlags.SelfRelative ) == 0 )
            { 
                throw new ArgumentException( 
                    Environment.GetResourceString( "AccessControl_InvalidSecurityDescriptorSelfRelativeForm" ),
                    "binaryForm" ); 
            }

            //
            // Extract the owner SID 
            //
 
            int ownerOffset = UnmarshalInt( binaryForm, offset + OwnerFoundAt ); 

            if ( ownerOffset != 0 ) 
            {
                owner = new SecurityIdentifier( binaryForm, offset + ownerOffset );
            }
            else 
            {
                owner = null; 
            } 

            // 
            // Extract the group SID
            //

            int groupOffset = UnmarshalInt( binaryForm, offset + GroupFoundAt ); 

            if ( groupOffset != 0 ) 
            { 
                group = new SecurityIdentifier( binaryForm, offset + groupOffset );
            } 
            else
            {
                group = null;
            } 

            // 
            // Extract the SACL 
            //
 
            int saclOffset = UnmarshalInt( binaryForm, offset + SaclFoundAt );

            if ((( flags & ControlFlags.SystemAclPresent ) != 0 ) &&
                saclOffset != 0 ) 
            {
                sacl = new RawAcl( binaryForm, offset + saclOffset ); 
            } 
            else
            { 
                sacl = null;
            }

            // 
            // Extract the DACL
            // 
 
            int daclOffset = UnmarshalInt( binaryForm, offset + DaclFoundAt );
 
            if ((( flags & ControlFlags.DiscretionaryAclPresent ) != 0 ) &&
                daclOffset != 0 )
            {
                dacl = new RawAcl( binaryForm, offset + daclOffset ); 
            }
            else 
            { 
                dacl = null;
            } 

            //
            // Create the resulting security descriptor
            // 

            CreateFromParts( flags, owner, group, sacl, dacl ); 
 
            //
            // In the offchance that the flags indicate that the rmControl 
            // field is meaningful, remember what was there.
            //

            if (( flags & ControlFlags.RMControlValid ) != 0 ) 
            {
                ResourceManagerControl = rmControl; 
            } 
        }
 
        #endregion

        #region Static Methods
 
        private static byte[] BinaryFormFromSddlForm( string sddlForm )
        { 
            if ( !IsSddlConversionSupported()) 
            {
                throw new PlatformNotSupportedException( Environment.GetResourceString( "PlatformNotSupported_Win9x" )); 
            }

            if ( sddlForm == null )
            { 
                throw new ArgumentNullException( "sddlForm" );
            } 
 
            int error;
            IntPtr byteArray = IntPtr.Zero; 
            uint byteArraySize = 0;
            const System.Int32 TRUE = 1;
            byte[] binaryForm = null;
 
            try
            { 
                if ( TRUE != Win32Native.ConvertStringSdToSd( 
                        sddlForm,
                        GenericSecurityDescriptor.Revision, 
                        out byteArray,
                        ref byteArraySize ))
                {
                    error = Marshal.GetLastWin32Error(); 

                    if ( error == Win32Native.ERROR_INVALID_PARAMETER || 
                        error == Win32Native.ERROR_INVALID_ACL || 
                        error == Win32Native.ERROR_INVALID_SECURITY_DESCR ||
                        error == Win32Native.ERROR_UNKNOWN_REVISION ) 
                    {
                        throw new ArgumentException(
                            Environment.GetResourceString( "ArgumentException_InvalidSDSddlForm" ),
                            "sddlForm" ); 
                    }
                    else if ( error == Win32Native.ERROR_NOT_ENOUGH_MEMORY ) 
                    { 
                        throw new OutOfMemoryException();
                    } 
                    else if ( error == Win32Native.ERROR_INVALID_SID )
                    {
                        throw new ArgumentException(
                            Environment.GetResourceString( "AccessControl_InvalidSidInSDDLString" ), 
                            "sddlForm" );
                    } 
                    else if ( error != Win32Native.ERROR_SUCCESS ) 
                    {
                        BCLDebug.Assert( false, string.Format( CultureInfo.InvariantCulture, "Unexpected error out of Win32.ConvertStringSdToSd: {0}", error )); 
                        throw new SystemException();
                    }
                }
 
                binaryForm = new byte[byteArraySize];
 
                // 
                // Extract the data from the returned pointer
                // 

                Marshal.Copy( byteArray, binaryForm, 0, ( int )byteArraySize );
            }
            finally 
            {
                // 
                // Now is a good time to get rid of the returned pointer 
                //
                if (byteArray != IntPtr.Zero) 
                {
                    Win32Native.LocalFree( byteArray );
                }
            } 

            return binaryForm; 
        } 

        #endregion 

        #region Public Properties

        // 
        // Allows retrieving the control bits for this security descriptor
        // Important: Special checks must be applied when setting flags and not 
        // all flags can be set (for instance, we only deal with self-relative 
        // security descriptors), thus flags can be set through other methods.
        // 

        public override ControlFlags ControlFlags
        {
            get 
            {
                return _flags; 
            } 
        }
 
        //
        // Allows retrieving and setting the owner SID for this security descriptor
        //
 
        public override SecurityIdentifier Owner
        { 
            get 
            {
                return _owner; 
            }

            set
            { 
                _owner = value;
            } 
        } 

        // 
        // Allows retrieving and setting the group SID for this security descriptor
        //

        public override SecurityIdentifier Group 
        {
            get 
            { 
                return _group;
            } 

            set
            {
                _group = value; 
            }
        } 
 
        //
        // Allows retrieving and setting the SACL for this security descriptor 
        //

        public RawAcl SystemAcl
        { 
            get
            { 
                return _sacl; 
            }
 
            set
            {
                _sacl = value;
            } 
        }
 
        // 
        // Allows retrieving and setting the DACL for this security descriptor
        // 

        public RawAcl DiscretionaryAcl
        {
            get 
            {
                return _dacl; 
            } 

            set 
            {
                _dacl = value;
            }
        } 

        // 
        // CORNER CASE (LEGACY) 
        // The ostensibly "reserved" field in the Security Descriptor header
        // can in fact be used by obscure resource managers which in this 
        // case must set the RMControlValid flag.
        //

        public byte ResourceManagerControl 
        {
            get 
            { 
                return _rmControl;
            } 

            set
            {
                _rmControl = value; 
            }
        } 
 

        #endregion 

        #region Public Methods

        public void SetFlags( ControlFlags flags ) 
        {
            // 
            // We can not deal with non-self-relative descriptors 
            // so just forget about it
            // 

            _flags = ( flags | ControlFlags.SelfRelative );
        }
 
        #endregion
    } 
 

    public sealed class CommonSecurityDescriptor : GenericSecurityDescriptor 
    {
        #region Private Members

        bool _isContainer; 
        bool _isDS;
        private RawSecurityDescriptor _rawSd; 
        private SystemAcl _sacl; 
        private DiscretionaryAcl _dacl;
 

        #endregion

        #region Private Methods 

        private void CreateFromParts( bool isContainer, bool isDS, ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, SystemAcl systemAcl, DiscretionaryAcl discretionaryAcl ) 
        { 
            if ( systemAcl != null &&
                systemAcl.IsContainer != isContainer ) 
            {
                throw new ArgumentException(
                    Environment.GetResourceString( isContainer ?
                        "AccessControl_MustSpecifyContainerAcl" : 
                        "AccessControl_MustSpecifyLeafObjectAcl" ),
                    "systemAcl" ); 
            } 

            if ( discretionaryAcl != null && 
                discretionaryAcl.IsContainer != isContainer )
            {
                throw new ArgumentException(
                    Environment.GetResourceString( isContainer ? 
                        "AccessControl_MustSpecifyContainerAcl" :
                        "AccessControl_MustSpecifyLeafObjectAcl" ), 
                    "discretionaryAcl" ); 
            }
 
            _isContainer = isContainer;

            if ( systemAcl != null &&
                systemAcl.IsDS != isDS ) 
            {
                throw new ArgumentException( 
                    Environment.GetResourceString( isDS ? 
                        "AccessControl_MustSpecifyDirectoryObjectAcl" :
                        "AccessControl_MustSpecifyNonDirectoryObjectAcl"), 
                    "systemAcl");
            }

            if ( discretionaryAcl != null && 
                discretionaryAcl.IsDS != isDS )
            { 
                throw new ArgumentException( 
                    Environment.GetResourceString( isDS ?
                        "AccessControl_MustSpecifyDirectoryObjectAcl" : 
                        "AccessControl_MustSpecifyNonDirectoryObjectAcl"),
                    "discretionaryAcl");
            }
 
            _isDS = isDS;
 
            _sacl = systemAcl; 

            // 
            // Replace null DACL with an allow-all for everyone DACL
            //

            if ( discretionaryAcl == null ) 
            {
                // 
                // to conform to native behavior, we will add allow everyone ace for DACL 
                //
 
                discretionaryAcl = DiscretionaryAcl.CreateAllowEveryoneFullAccess(_isDS, _isContainer);
            }

            _dacl = discretionaryAcl; 

            // 
            // DACL is never null. So always set the flag bit on 
            //
 
            ControlFlags actualFlags = flags | ControlFlags.DiscretionaryAclPresent;

            //
            // Keep SACL and the flag bit in [....]. 
            //
 
            if (systemAcl == null) 
            {
                unchecked { actualFlags &= ~(ControlFlags.SystemAclPresent); } 
            }
            else
            {
                actualFlags |= (ControlFlags.SystemAclPresent); 
            }
 
            _rawSd = new RawSecurityDescriptor( actualFlags, owner, group, systemAcl == null ? null : systemAcl.RawAcl, discretionaryAcl.RawAcl ); 
        }
 
        #endregion

        #region Constructors
 
        //
        // Creates a security descriptor explicitly 
        // 

        public CommonSecurityDescriptor( bool isContainer, bool isDS, ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, SystemAcl systemAcl, DiscretionaryAcl discretionaryAcl ) 
        {
            CreateFromParts( isContainer, isDS, flags, owner, group, systemAcl, discretionaryAcl );
        }
 
        private CommonSecurityDescriptor( bool isContainer, bool isDS, ControlFlags flags, SecurityIdentifier owner, SecurityIdentifier group, RawAcl systemAcl, RawAcl discretionaryAcl )
            : this( isContainer, isDS, flags, owner, group, systemAcl == null ? null : new SystemAcl( isContainer, isDS, systemAcl ), discretionaryAcl == null ? null : new DiscretionaryAcl( isContainer, isDS, discretionaryAcl )) 
        { 
        }
 
        public CommonSecurityDescriptor( bool isContainer, bool isDS, RawSecurityDescriptor rawSecurityDescriptor )
            : this( isContainer, isDS, rawSecurityDescriptor, false )
        {
        } 

        internal CommonSecurityDescriptor( bool isContainer, bool isDS, RawSecurityDescriptor rawSecurityDescriptor, bool trusted ) 
        { 
            if ( rawSecurityDescriptor == null )
            { 
                throw new ArgumentNullException( "rawSecurityDescriptor" );
            }

            CreateFromParts( 
                isContainer,
                isDS, 
                rawSecurityDescriptor.ControlFlags, 
                rawSecurityDescriptor.Owner,
                rawSecurityDescriptor.Group, 
                rawSecurityDescriptor.SystemAcl == null ? null : new SystemAcl( isContainer, isDS, rawSecurityDescriptor.SystemAcl, trusted ),
                rawSecurityDescriptor.DiscretionaryAcl == null ? null : new DiscretionaryAcl( isContainer, isDS, rawSecurityDescriptor.DiscretionaryAcl, trusted ));
        }
 
        //
        // Create a security descriptor from an SDDL string 
        // 

        public CommonSecurityDescriptor( bool isContainer, bool isDS, string sddlForm ) 
            : this( isContainer, isDS, new RawSecurityDescriptor( sddlForm ), true )
        {
        }
 
        //
        // Create a security descriptor from its binary representation 
        // 

        public CommonSecurityDescriptor( bool isContainer, bool isDS, byte[] binaryForm, int offset ) 
            : this( isContainer, isDS, new RawSecurityDescriptor( binaryForm, offset ), true )
        {
        }
 
        #endregion
 
        #region Protected Properties 

        internal sealed override GenericAcl GenericSacl 
        {
            get { return _sacl; }
        }
 
        internal sealed override GenericAcl GenericDacl
        { 
            get { return _dacl; } 
        }
 
        #endregion

        #region Public Properties
 
        public bool IsContainer
        { 
            get { return _isContainer; } 
        }
 
        public bool IsDS
        {
            get { return _isDS; }
        } 

 
        // 
        // Allows retrieving the control bits for this security descriptor
        // 

        public override ControlFlags ControlFlags
        {
            get 
            {
                return _rawSd.ControlFlags; 
            } 
        }
 
        //
        // Allows retrieving and setting the owner SID for this security descriptor
        //
 
        public override SecurityIdentifier Owner
        { 
            get 
            {
                return _rawSd.Owner; 
            }

            set
            { 
                _rawSd.Owner = value;
            } 
        } 

        // 
        // Allows retrieving and setting the group SID for this security descriptor
        //

        public override SecurityIdentifier Group 
        {
            get 
            { 
                return _rawSd.Group;
            } 

            set
            {
                _rawSd.Group = value; 
            }
        } 
 

        public SystemAcl SystemAcl 
        {
            get
            {
                return _sacl; 
            }
 
            set 
            {
                if ( value != null ) 
                {
                    if ( value.IsContainer != this.IsContainer )
                    {
                        throw new ArgumentException( 
                            Environment.GetResourceString( this.IsContainer ?
                                "AccessControl_MustSpecifyContainerAcl" : 
                                "AccessControl_MustSpecifyLeafObjectAcl" ), 
                            "value" );
                    } 

                    if ( value.IsDS != this.IsDS )
                    {
                        throw new ArgumentException( 
                            Environment.GetResourceString(this.IsDS ?
                                "AccessControl_MustSpecifyDirectoryObjectAcl" : 
                                "AccessControl_MustSpecifyNonDirectoryObjectAcl"), 
                            "value");
                    } 
                }

                _sacl = value;
 
                if ( _sacl != null )
                { 
                    _rawSd.SystemAcl = _sacl.RawAcl; 
                    AddControlFlags( ControlFlags.SystemAclPresent );
                } 
                else
                {
                    _rawSd.SystemAcl = null;
                    RemoveControlFlags( ControlFlags.SystemAclPresent ); 
                }
            } 
        } 

        // 
        // Allows retrieving and setting the DACL for this security descriptor
        //

        public DiscretionaryAcl DiscretionaryAcl 
        {
            get 
            { 
                return _dacl;
            } 

            set
            {
                if ( value != null ) 
                {
                    if ( value.IsContainer != this.IsContainer ) 
                    { 
                        throw new ArgumentException(
                            Environment.GetResourceString( this.IsContainer ? 
                                "AccessControl_MustSpecifyContainerAcl" :
                                "AccessControl_MustSpecifyLeafObjectAcl" ),
                            "value" );
                    } 

                    if ( value.IsDS != this.IsDS ) 
                    { 
                        throw new ArgumentException(
                            Environment.GetResourceString( this.IsDS ? 
                                "AccessControl_MustSpecifyDirectoryObjectAcl" :
                                "AccessControl_MustSpecifyNonDirectoryObjectAcl"),
                            "value");
                    } 
                }
 
                // 
                // NULL DACLs are replaced with allow everyone full access DACLs.
                // 

                if ( value == null )
                {
                    _dacl = DiscretionaryAcl.CreateAllowEveryoneFullAccess(IsDS, IsContainer); 
                }
                else 
                { 
                    _dacl = value;
                } 

                _rawSd.DiscretionaryAcl = _dacl.RawAcl;
                AddControlFlags( ControlFlags.DiscretionaryAclPresent );
            } 
        }
 
        public bool IsSystemAclCanonical 
        {
            get { return ( SystemAcl == null || SystemAcl.IsCanonical ); } 
        }

        public bool IsDiscretionaryAclCanonical
        { 
            get { return ( DiscretionaryAcl == null || DiscretionaryAcl.IsCanonical ); }
        } 
 
        #endregion
 
        #region Public Methods

        public void SetSystemAclProtection( bool isProtected, bool preserveInheritance )
        { 
            if ( !isProtected )
            { 
                RemoveControlFlags( ControlFlags.SystemAclProtected ); 
            }
            else 
            {
                if ( !preserveInheritance && SystemAcl != null )
                {
                    SystemAcl.RemoveInheritedAces(); 
                }
 
                AddControlFlags( ControlFlags.SystemAclProtected ); 
            }
        } 

        public void SetDiscretionaryAclProtection( bool isProtected, bool preserveInheritance )
        {
            if ( !isProtected ) 
            {
                RemoveControlFlags( ControlFlags.DiscretionaryAclProtected ); 
            } 
            else
            { 
                if ( !preserveInheritance && DiscretionaryAcl != null )
                {
                    DiscretionaryAcl.RemoveInheritedAces();
                } 

                AddControlFlags( ControlFlags.DiscretionaryAclProtected ); 
            } 
            if (DiscretionaryAcl != null && DiscretionaryAcl.EveryOneFullAccessForNullDacl)
            { 
                DiscretionaryAcl.EveryOneFullAccessForNullDacl = false;
            }
        }
 
        public void PurgeAccessControl( SecurityIdentifier sid )
        { 
            if ( sid == null ) 
            {
                throw new ArgumentNullException( "sid" ); 
            }

            if ( DiscretionaryAcl != null )
            { 
                DiscretionaryAcl.Purge( sid );
            } 
        } 

        public void PurgeAudit( SecurityIdentifier sid ) 
        {
            if ( sid == null )
            {
                throw new ArgumentNullException( "sid" ); 
            }
 
            if ( SystemAcl != null ) 
            {
                SystemAcl.Purge( sid ); 
            }
        }

        #endregion 

        #region internal Methods 
        internal void UpdateControlFlags(ControlFlags flagsToUpdate, ControlFlags newFlags) 
        {
            ControlFlags finalFlags = newFlags | (_rawSd.ControlFlags & (~flagsToUpdate)); 
            _rawSd.SetFlags(finalFlags);
        }

        // 
        // These two add/remove method must be called with great care (and thus it is internal)
        // The caller is responsible for keeping the SaclPresent and DaclPresent bits in [....] 
        // with the actual SACL and DACL. 
        //
 
        internal void AddControlFlags(ControlFlags flags)
        {
            _rawSd.SetFlags(_rawSd.ControlFlags | flags);
        } 

        internal void RemoveControlFlags(ControlFlags flags) 
        { 
            unchecked
            { 
                _rawSd.SetFlags(_rawSd.ControlFlags & ~flags);
            }
        }
 
        internal bool IsSystemAclPresent
        { 
            get 
            {
                return (_rawSd.ControlFlags & ControlFlags.SystemAclPresent) != 0; 
            }
        }

        internal bool IsDiscretionaryAclPresent 
        {
            get 
            { 
                return (_rawSd.ControlFlags & ControlFlags.DiscretionaryAclPresent) != 0;
            } 
        }
        #endregion
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK