288 lines
8.9 KiB
C#
288 lines
8.9 KiB
C#
// This code is derived from jcifs smb client library <jcifs at samba dot org>
|
|
// Ported by J. Arturo <webmaster at komodosoft dot net>
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2.1 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
using System.Text;
|
|
using SharpCifs.Util;
|
|
|
|
namespace SharpCifs.Smb
|
|
{
|
|
/// <summary>
|
|
/// An Access Control Entry (ACE) is an element in a security descriptor
|
|
/// such as those associated with files and directories.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// <p>
|
|
/// 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).
|
|
/// <p>
|
|
/// 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 <i>any</i> 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 <i>all</i> 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.
|
|
/// <p>
|
|
/// For example, if user <tt>WNET\alice</tt> tries to open a file
|
|
/// with desired access bits <tt>0x00000003</tt> (<tt>FILE_READ_DATA |
|
|
/// FILE_WRITE_DATA</tt>) and the target file has the following security
|
|
/// descriptor ACEs:
|
|
/// <pre>
|
|
/// Allow WNET\alice 0x001200A9 Direct
|
|
/// Allow Administrators 0x001F01FF Inherited
|
|
/// Allow SYSTEM 0x001F01FF Inherited
|
|
/// </pre>
|
|
/// the access check would fail because the direct ACE has an access mask
|
|
/// of <tt>0x001200A9</tt> which doesn't have the
|
|
/// <tt>FILE_WRITE_DATA</tt> bit on (bit <tt>0x00000002</tt>). Actually, this isn't quite correct. If
|
|
/// <tt>WNET\alice</tt> is in the local <tt>Administrators</tt> group the access check
|
|
/// will succeed because the inherited ACE allows local <tt>Administrators</tt>
|
|
/// both <tt>FILE_READ_DATA</tt> and <tt>FILE_WRITE_DATA</tt> access.
|
|
/// </remarks>
|
|
public class Ace
|
|
{
|
|
public const int FileReadData = unchecked(0x00000001);
|
|
|
|
public const int FileWriteData = unchecked(0x00000002);
|
|
|
|
public const int FileAppendData = unchecked(0x00000004);
|
|
|
|
public const int FileReadEa = unchecked(0x00000008);
|
|
|
|
public const int FileWriteEa = unchecked(0x00000010);
|
|
|
|
public const int FileExecute = unchecked(0x00000020);
|
|
|
|
public const int FileDelete = unchecked(0x00000040);
|
|
|
|
public const int FileReadAttributes = unchecked(0x00000080);
|
|
|
|
public const int FileWriteAttributes = unchecked(0x00000100);
|
|
|
|
public const int Delete = unchecked(0x00010000);
|
|
|
|
public const int ReadControl = unchecked(0x00020000);
|
|
|
|
public const int WriteDac = unchecked(0x00040000);
|
|
|
|
public const int WriteOwner = unchecked(0x00080000);
|
|
|
|
public const int Synchronize = unchecked(0x00100000);
|
|
|
|
public const int GenericAll = unchecked(0x10000000);
|
|
|
|
public const int GenericExecute = unchecked(0x20000000);
|
|
|
|
public const int GenericWrite = unchecked(0x40000000);
|
|
|
|
public const int GenericRead = unchecked((int)(0x80000000));
|
|
|
|
public const int FlagsObjectInherit = unchecked(0x01);
|
|
|
|
public const int FlagsContainerInherit = unchecked(0x02);
|
|
|
|
public const int FlagsNoPropagate = unchecked(0x04);
|
|
|
|
public const int FlagsInheritOnly = unchecked(0x08);
|
|
|
|
public const int FlagsInherited = unchecked(0x10);
|
|
|
|
internal bool Allow;
|
|
|
|
internal int Flags;
|
|
|
|
internal int Access;
|
|
|
|
internal Sid Sid;
|
|
|
|
// 1
|
|
// 2
|
|
// 3
|
|
// 4
|
|
// 5
|
|
// 6
|
|
// 7
|
|
// 8
|
|
// 9
|
|
// 16
|
|
// 17
|
|
// 18
|
|
// 19
|
|
// 20
|
|
// 28
|
|
// 29
|
|
// 30
|
|
// 31
|
|
/// <summary>Returns true if this ACE is an allow ACE and false if it is a deny ACE.</summary>
|
|
/// <remarks>Returns true if this ACE is an allow ACE and false if it is a deny ACE.</remarks>
|
|
public virtual bool IsAllow()
|
|
{
|
|
return Allow;
|
|
}
|
|
|
|
/// <summary>Returns true if this ACE is an inherited ACE and false if it is a direct ACE.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Returns true if this ACE is an inherited ACE and false if it is a direct ACE.
|
|
/// <p>
|
|
/// Note: For reasons not fully understood, <tt>FLAGS_INHERITED</tt> may
|
|
/// not be set within all security descriptors even though the ACE was in
|
|
/// face inherited. If an inherited ACE is added to a parent the Windows
|
|
/// ACL editor will rebuild all children ACEs and set this flag accordingly.
|
|
/// </remarks>
|
|
public virtual bool IsInherited()
|
|
{
|
|
return (Flags & FlagsInherited) != 0;
|
|
}
|
|
|
|
/// <summary>Returns the flags for this ACE.</summary>
|
|
/// <remarks>
|
|
/// Returns the flags for this ACE. The </tt>isInherited()</tt>
|
|
/// method checks the <tt>FLAGS_INHERITED</tt> bit in these flags.
|
|
/// </remarks>
|
|
public virtual int GetFlags()
|
|
{
|
|
return Flags;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the 'Apply To' text for inheritance of ACEs on
|
|
/// directories such as 'This folder, subfolder and files'.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Returns the 'Apply To' text for inheritance of ACEs on
|
|
/// directories such as 'This folder, subfolder and files'. For
|
|
/// files the text is always 'This object only'.
|
|
/// </remarks>
|
|
public virtual string GetApplyToText()
|
|
{
|
|
switch (Flags & (FlagsObjectInherit | FlagsContainerInherit | FlagsInheritOnly
|
|
))
|
|
{
|
|
case unchecked(0x00):
|
|
{
|
|
return "This folder only";
|
|
}
|
|
|
|
case unchecked(0x03):
|
|
{
|
|
return "This folder, subfolders and files";
|
|
}
|
|
|
|
case unchecked(0x0B):
|
|
{
|
|
return "Subfolders and files only";
|
|
}
|
|
|
|
case unchecked(0x02):
|
|
{
|
|
return "This folder and subfolders";
|
|
}
|
|
|
|
case unchecked(0x0A):
|
|
{
|
|
return "Subfolders only";
|
|
}
|
|
|
|
case unchecked(0x01):
|
|
{
|
|
return "This folder and files";
|
|
}
|
|
|
|
case unchecked(0x09):
|
|
{
|
|
return "Files only";
|
|
}
|
|
}
|
|
return "Invalid";
|
|
}
|
|
|
|
/// <summary>Returns the access mask accociated with this ACE.</summary>
|
|
/// <remarks>
|
|
/// Returns the access mask accociated with this ACE. Use the
|
|
/// constants for <tt>FILE_READ_DATA</tt>, <tt>FILE_WRITE_DATA</tt>,
|
|
/// <tt>READ_CONTROL</tt>, <tt>GENERIC_ALL</tt>, etc with bitwise
|
|
/// operators to determine which bits of the mask are on or off.
|
|
/// </remarks>
|
|
public virtual int GetAccessMask()
|
|
{
|
|
return Access;
|
|
}
|
|
|
|
/// <summary>Return the SID associated with this ACE.</summary>
|
|
/// <remarks>Return the SID associated with this ACE.</remarks>
|
|
public virtual Sid GetSid()
|
|
{
|
|
return Sid;
|
|
}
|
|
|
|
internal virtual int Decode(byte[] buf, int bi)
|
|
{
|
|
Allow = buf[bi++] == unchecked(unchecked(0x00));
|
|
Flags = buf[bi++] & unchecked(0xFF);
|
|
int size = ServerMessageBlock.ReadInt2(buf, bi);
|
|
bi += 2;
|
|
Access = ServerMessageBlock.ReadInt4(buf, bi);
|
|
bi += 4;
|
|
Sid = new Sid(buf, bi);
|
|
return size;
|
|
}
|
|
|
|
internal virtual void AppendCol(StringBuilder sb, string str, int width)
|
|
{
|
|
sb.Append(str);
|
|
int count = width - str.Length;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
sb.Append(' ');
|
|
}
|
|
}
|
|
|
|
/// <summary>Return a string represeting this ACE.</summary>
|
|
/// <remarks>
|
|
/// Return a string represeting this ACE.
|
|
/// <p>
|
|
/// Note: This function should probably be changed to return SDDL
|
|
/// fragments but currently it does not.
|
|
/// </remarks>
|
|
public override string ToString()
|
|
{
|
|
int count;
|
|
int i;
|
|
string str;
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.Append(IsAllow() ? "Allow " : "Deny ");
|
|
AppendCol(sb, Sid.ToDisplayString(), 25);
|
|
sb.Append(" 0x").Append(Hexdump.ToHexString(Access, 8)).Append(' ');
|
|
sb.Append(IsInherited() ? "Inherited " : "Direct ");
|
|
AppendCol(sb, GetApplyToText(), 34);
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
}
|