/
ACE.java
169 lines (146 loc) · 5.43 KB
/
ACE.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
*
* 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
*/
package jcifs.internal.dtyp;
import jcifs.Decodable;
import jcifs.internal.util.SMBUtil;
import jcifs.smb.SID;
import jcifs.util.Hexdump;
/**
* 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.
*
* @internal
*/
public class ACE implements jcifs.ACE, Decodable {
boolean allow;
int flags;
int access;
SID sid;
@Override
public boolean isAllow () {
return this.allow;
}
@Override
public boolean isInherited () {
return ( this.flags & FLAGS_INHERITED ) != 0;
}
@Override
public int getFlags () {
return this.flags;
}
@Override
public String getApplyToText () {
switch ( this.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";
}
@Override
public int getAccessMask () {
return this.access;
}
@Override
public SID getSID () {
return this.sid;
}
@Override
public int decode ( byte[] buf, int bi, int len ) {
this.allow = buf[ bi++ ] == (byte) 0x00;
this.flags = buf[ bi++ ] & 0xFF;
int size = SMBUtil.readInt2(buf, bi);
bi += 2;
this.access = SMBUtil.readInt4(buf, bi);
bi += 4;
this.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.
*/
@Override
public String toString () {
StringBuffer sb = new StringBuffer();
sb.append(isAllow() ? "Allow " : "Deny ");
appendCol(sb, this.sid.toDisplayString(), 25);
sb.append(" 0x").append(Hexdump.toHexString(this.access, 8)).append(' ');
sb.append(isInherited() ? "Inherited " : "Direct ");
appendCol(sb, getApplyToText(), 34);
return sb.toString();
}
}