An Access Control Entry (ACE) is an element in a security descriptor such as those associated with files and directories.
An Access Control Entry (ACE) is an element in a security descriptor such as those associated with files and directories. The Windows OS determines which users have the necessary permissions to access objects based on these entries.

To fully understand the information exposed by this class a description of the access check algorithm used by Windows is required. The following is a basic description of the algorithm. For a more complete description we recommend reading the section on Access Control in Keith Brown's "The .NET Developer's Guide to Windows Security" (which is also available online).

Direct ACEs are evaluated first in order. The SID of the user performing the operation and the desired access bits are compared to the SID and access mask of each ACE. If the SID matches, the allow/deny flags and access mask are considered. If the ACE is a "deny" ACE and any of the desired access bits match bits in the access mask of the ACE, the whole access check fails. If the ACE is an "allow" ACE and all of the bits in the desired access bits match bits in the access mask of the ACE, the access check is successful. Otherwise, more ACEs are evaluated until all desired access bits (combined) are "allowed". If all of the desired access bits are not "allowed" the then same process is repeated for inherited ACEs.

For example, if user WNET\alice tries to open a file with desired access bits 0x00000003 (FILE_READ_DATA | FILE_WRITE_DATA) and the target file has the following security descriptor ACEs:

 Allow WNET\alice     0x001200A9  Direct Allow Administrators 0x001F01FF  Inherited Allow SYSTEM         0x001F01FF  Inherited 
the access check would fail because the direct ACE has an access mask of 0x001200A9 which doesn't have the FILE_WRITE_DATA bit on (bit 0x00000002). Actually, this isn't quite correct. If WNET\alice is in the local Administrators group the access check will succeed because the inherited ACE allows local Administrators both FILE_READ_DATA and FILE_WRITE_DATA access.
        /// <exception cref="System.IO.IOException"></exception>
        public virtual int Decode(byte[] buffer, int bufferIndex, int len)
        {
            int start = bufferIndex;

            bufferIndex++;
            // revision
            bufferIndex++;
            Type         = ServerMessageBlock.ReadInt2(buffer, bufferIndex);
            bufferIndex += 2;
            ServerMessageBlock.ReadInt4(buffer, bufferIndex);
            // offset to owner sid
            bufferIndex += 4;
            ServerMessageBlock.ReadInt4(buffer, bufferIndex);
            // offset to group sid
            bufferIndex += 4;
            ServerMessageBlock.ReadInt4(buffer, bufferIndex);
            // offset to sacl
            bufferIndex += 4;
            int daclOffset = ServerMessageBlock.ReadInt4(buffer, bufferIndex);

            bufferIndex = start + daclOffset;
            bufferIndex++;
            // revision
            bufferIndex++;
            int size = ServerMessageBlock.ReadInt2(buffer, bufferIndex);

            bufferIndex += 2;
            int numAces = ServerMessageBlock.ReadInt4(buffer, bufferIndex);

            bufferIndex += 4;
            if (numAces > 4096)
            {
                throw new IOException("Invalid SecurityDescriptor");
            }
            if (daclOffset != 0)
            {
                Aces = new Ace[numAces];
                for (int i = 0; i < numAces; i++)
                {
                    Aces[i]      = new Ace();
                    bufferIndex += Aces[i].Decode(buffer, bufferIndex);
                }
            }
            else
            {
                Aces = null;
            }
            return(bufferIndex - start);
        }
		/// <exception cref="System.IO.IOException"></exception>
		public virtual int Decode(byte[] buffer, int bufferIndex, int len)
		{
			int start = bufferIndex;
			bufferIndex++;
			// revision
			bufferIndex++;
			Type = ServerMessageBlock.ReadInt2(buffer, bufferIndex);
			bufferIndex += 2;
			ServerMessageBlock.ReadInt4(buffer, bufferIndex);
			// offset to owner sid
			bufferIndex += 4;
			ServerMessageBlock.ReadInt4(buffer, bufferIndex);
			// offset to group sid
			bufferIndex += 4;
			ServerMessageBlock.ReadInt4(buffer, bufferIndex);
			// offset to sacl
			bufferIndex += 4;
			int daclOffset = ServerMessageBlock.ReadInt4(buffer, bufferIndex);
			bufferIndex = start + daclOffset;
			bufferIndex++;
			// revision
			bufferIndex++;
			int size = ServerMessageBlock.ReadInt2(buffer, bufferIndex);
			bufferIndex += 2;
			int numAces = ServerMessageBlock.ReadInt4(buffer, bufferIndex);
			bufferIndex += 4;
			if (numAces > 4096)
			{
				throw new IOException("Invalid SecurityDescriptor");
			}
			if (daclOffset != 0)
			{
				Aces = new Ace[numAces];
				for (int i = 0; i < numAces; i++)
				{
					Aces[i] = new Ace();
					bufferIndex += Aces[i].Decode(buffer, bufferIndex);
				}
			}
			else
			{
				Aces = null;
			}
			return bufferIndex - start;
		}
Example #3
0
 /// <exception cref="System.IO.IOException"></exception>
 private void ProcessAces(Ace[] aces, bool resolveSids)
 {
     string server = GetServerWithDfs();
     int ai;
     if (resolveSids)
     {
         Sid[] sids = new Sid[aces.Length];
         string[] names = null;
         for (ai = 0; ai < aces.Length; ai++)
         {
             sids[ai] = aces[ai].Sid;
         }
         for (int off = 0; off < sids.Length; off += 64)
         {
             int len = sids.Length - off;
             if (len > 64)
             {
                 len = 64;
             }
             Sid.ResolveSids(server, Auth, sids, off, len);
         }
     }
     else
     {
         for (ai = 0; ai < aces.Length; ai++)
         {
             aces[ai].Sid.OriginServer = server;
             aces[ai].Sid.OriginAuth = Auth;
         }
     }
 }