package jcifs.smb;
import jcifs.util.Hexdump;
import java.io.IOException;
/**
* 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.
*/
public class ACE {
public static final int FILE_READ_DATA = 0x00000001; // 1
public static final int FILE_WRITE_DATA = 0x00000002; // 2
public static final int FILE_APPEND_DATA = 0x00000004; // 3
public static final int FILE_READ_EA = 0x00000008; // 4
public static final int FILE_WRITE_EA = 0x00000010; // 5
public static final int FILE_EXECUTE = 0x00000020; // 6
public static final int FILE_DELETE = 0x00000040; // 7
public static final int FILE_READ_ATTRIBUTES = 0x00000080; // 8
public static final int FILE_WRITE_ATTRIBUTES = 0x00000100; // 9
public static final int DELETE = 0x00010000; // 16
public static final int READ_CONTROL = 0x00020000; // 17
public static final int WRITE_DAC = 0x00040000; // 18
public static final int WRITE_OWNER = 0x00080000; // 19
public static final int SYNCHRONIZE = 0x00100000; // 20
public static final int GENERIC_ALL = 0x10000000; // 28
public static final int GENERIC_EXECUTE = 0x20000000; // 29
public static final int GENERIC_WRITE = 0x40000000; // 30
public static final int GENERIC_READ = 0x80000000; // 31
public static final int FLAGS_OBJECT_INHERIT = 0x01;
public static final int FLAGS_CONTAINER_INHERIT = 0x02;
public static final int FLAGS_NO_PROPAGATE = 0x04;
public static final int FLAGS_INHERIT_ONLY = 0x08;
public static final int FLAGS_INHERITED = 0x10;
boolean allow;
int flags;
int access;
SID sid;
/**
* Returns true if this ACE is an allow ACE and false if it is a deny ACE.
*/
public boolean isAllow() {
return allow;
}
/**
* 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.
*/
public boolean isInherited() {
return (flags & FLAGS_INHERITED) != 0;
}
/**
* Returns the flags for this ACE. The </tt>isInherited()</tt>
* method checks the <tt>FLAGS_INHERITED</tt> bit in these flags.
*/
public int getFlags() {
return flags;
}
/**
* 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'.
*/
public String getApplyToText() {
switch (flags & (FLAGS_OBJECT_INHERIT | FLAGS_CONTAINER_INHERIT | FLAGS_INHERIT_ONLY)) {
case 0x00:
return "This folder only";
case 0x03:
return "This folder, subfolders and files";
case 0x0B:
return "Subfolders and files only";
case 0x02:
return "This folder and subfolders";
case 0x0A:
return "Subfolders only";
case 0x01:
return "This folder and files";
case 0x09:
return "Files only";
}
return "Invalid";
}
/**
* 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.
*/
public int getAccessMask() {
return access;
}
/**
* Return the SID associated with this ACE.
*/
public SID getSID() {
return sid;
}
int decode( byte[] buf, int bi ) {
allow = buf[bi++] == (byte)0x00;
flags = buf[bi++] & 0xFF;
int size = ServerMessageBlock.readInt2(buf, bi);
bi += 2;
access = ServerMessageBlock.readInt4(buf, bi);
bi += 4;
sid = new SID(buf, bi);
return size;
}
void appendCol(StringBuffer sb, String str, int width) {
sb.append(str);
int count = width - str.length();
for (int i = 0; i < count; i++) {
sb.append(' ');
}
}
/**
* Return a string represeting this ACE.
* <p>
* Note: This function should probably be changed to return SDDL
* fragments but currently it does not.
*/
public String toString() {
int count, i;
String str;
StringBuffer sb = new StringBuffer();
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();
}
}