|
1 /* |
|
2 * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package sun.nio.fs; |
|
27 |
|
28 import java.nio.file.ProviderMismatchException; |
|
29 import java.nio.file.attribute.*; |
|
30 import java.util.*; |
|
31 import java.io.IOException; |
|
32 import sun.misc.Unsafe; |
|
33 |
|
34 import static sun.nio.fs.WindowsNativeDispatcher.*; |
|
35 import static sun.nio.fs.WindowsConstants.*; |
|
36 |
|
37 /** |
|
38 * A SecurityDescriptor for use when setting a file's ACL or creating a file |
|
39 * with an initial ACL. |
|
40 */ |
|
41 |
|
42 class WindowsSecurityDescriptor { |
|
43 private static final Unsafe unsafe = Unsafe.getUnsafe(); |
|
44 |
|
45 /** |
|
46 * typedef struct _ACL { |
|
47 * BYTE AclRevision; |
|
48 * BYTE Sbz1; |
|
49 * WORD AclSize; |
|
50 * WORD AceCount; |
|
51 * WORD Sbz2; |
|
52 * } ACL; |
|
53 * |
|
54 * typedef struct _ACE_HEADER { |
|
55 * BYTE AceType; |
|
56 * BYTE AceFlags; |
|
57 * WORD AceSize; |
|
58 * } ACE_HEADER; |
|
59 * |
|
60 * typedef struct _ACCESS_ALLOWED_ACE { |
|
61 * ACE_HEADER Header; |
|
62 * ACCESS_MASK Mask; |
|
63 * DWORD SidStart; |
|
64 * } ACCESS_ALLOWED_ACE; |
|
65 * |
|
66 * typedef struct _ACCESS_DENIED_ACE { |
|
67 * ACE_HEADER Header; |
|
68 * ACCESS_MASK Mask; |
|
69 * DWORD SidStart; |
|
70 * } ACCESS_DENIED_ACE; |
|
71 * |
|
72 * typedef struct _SECURITY_DESCRIPTOR { |
|
73 * BYTE Revision; |
|
74 * BYTE Sbz1; |
|
75 * SECURITY_DESCRIPTOR_CONTROL Control; |
|
76 * PSID Owner; |
|
77 * PSID Group; |
|
78 * PACL Sacl; |
|
79 * PACL Dacl; |
|
80 * } SECURITY_DESCRIPTOR; |
|
81 */ |
|
82 private static final short SIZEOF_ACL = 8; |
|
83 private static final short SIZEOF_ACCESS_ALLOWED_ACE = 12; |
|
84 private static final short SIZEOF_ACCESS_DENIED_ACE = 12; |
|
85 private static final short SIZEOF_SECURITY_DESCRIPTOR = 20; |
|
86 |
|
87 private static final short OFFSETOF_TYPE = 0; |
|
88 private static final short OFFSETOF_FLAGS = 1; |
|
89 private static final short OFFSETOF_ACCESS_MASK = 4; |
|
90 private static final short OFFSETOF_SID = 8; |
|
91 |
|
92 // null security descriptor |
|
93 private static final WindowsSecurityDescriptor NULL_DESCRIPTOR = |
|
94 new WindowsSecurityDescriptor(); |
|
95 |
|
96 // native resources |
|
97 private final List<Long> sidList; |
|
98 private final NativeBuffer aclBuffer, sdBuffer; |
|
99 |
|
100 /** |
|
101 * Creates the "null" SecurityDescriptor |
|
102 */ |
|
103 private WindowsSecurityDescriptor() { |
|
104 this.sidList = null; |
|
105 this.aclBuffer = null; |
|
106 this.sdBuffer = null; |
|
107 } |
|
108 |
|
109 /** |
|
110 * Creates a SecurityDescriptor from the given ACL |
|
111 */ |
|
112 private WindowsSecurityDescriptor(List<AclEntry> acl) throws IOException { |
|
113 boolean initialized = false; |
|
114 |
|
115 // SECURITY: need to copy list in case size changes during processing |
|
116 acl = new ArrayList<AclEntry>(acl); |
|
117 |
|
118 // list of SIDs |
|
119 sidList = new ArrayList<Long>(acl.size()); |
|
120 try { |
|
121 // initial size of ACL |
|
122 int size = SIZEOF_ACL; |
|
123 |
|
124 // get the SID for each entry |
|
125 for (AclEntry entry: acl) { |
|
126 UserPrincipal user = entry.principal(); |
|
127 if (!(user instanceof WindowsUserPrincipals.User)) |
|
128 throw new ProviderMismatchException(); |
|
129 String sidString = ((WindowsUserPrincipals.User)user).sidString(); |
|
130 try { |
|
131 long pSid = ConvertStringSidToSid(sidString); |
|
132 sidList.add(pSid); |
|
133 |
|
134 // increase size to allow for entry |
|
135 size += GetLengthSid(pSid) + |
|
136 Math.max(SIZEOF_ACCESS_ALLOWED_ACE, SIZEOF_ACCESS_DENIED_ACE); |
|
137 |
|
138 } catch (WindowsException x) { |
|
139 throw new IOException("Failed to get SID for " + user.getName() |
|
140 + ": " + x.errorString()); |
|
141 } |
|
142 } |
|
143 |
|
144 // allocate memory for the ACL |
|
145 aclBuffer = NativeBuffers.getNativeBuffer(size); |
|
146 sdBuffer = NativeBuffers.getNativeBuffer(SIZEOF_SECURITY_DESCRIPTOR); |
|
147 |
|
148 InitializeAcl(aclBuffer.address(), size); |
|
149 |
|
150 // Add entry ACE to the ACL |
|
151 int i = 0; |
|
152 while (i < acl.size()) { |
|
153 AclEntry entry = acl.get(i); |
|
154 long pSid = sidList.get(i); |
|
155 try { |
|
156 encode(entry, pSid, aclBuffer.address()); |
|
157 } catch (WindowsException x) { |
|
158 throw new IOException("Failed to encode ACE: " + |
|
159 x.errorString()); |
|
160 } |
|
161 i++; |
|
162 } |
|
163 |
|
164 // initialize security descriptor and set DACL |
|
165 InitializeSecurityDescriptor(sdBuffer.address()); |
|
166 SetSecurityDescriptorDacl(sdBuffer.address(), aclBuffer.address()); |
|
167 initialized = true; |
|
168 } catch (WindowsException x) { |
|
169 throw new IOException(x.getMessage()); |
|
170 } finally { |
|
171 // release resources if not completely initialized |
|
172 if (!initialized) |
|
173 release(); |
|
174 } |
|
175 } |
|
176 |
|
177 /** |
|
178 * Releases memory associated with SecurityDescriptor |
|
179 */ |
|
180 void release() { |
|
181 if (sdBuffer != null) |
|
182 sdBuffer.release(); |
|
183 if (aclBuffer != null) |
|
184 aclBuffer.release(); |
|
185 if (sidList != null) { |
|
186 // release memory for SIDs |
|
187 for (Long sid: sidList) { |
|
188 LocalFree(sid); |
|
189 } |
|
190 } |
|
191 } |
|
192 |
|
193 /** |
|
194 * Returns address of SecurityDescriptor |
|
195 */ |
|
196 long address() { |
|
197 return (sdBuffer == null) ? 0L : sdBuffer.address(); |
|
198 } |
|
199 |
|
200 // decode Windows ACE to NFSv4 AclEntry |
|
201 private static AclEntry decode(long aceAddress) |
|
202 throws IOException |
|
203 { |
|
204 // map type |
|
205 byte aceType = unsafe.getByte(aceAddress + OFFSETOF_TYPE); |
|
206 if (aceType != ACCESS_ALLOWED_ACE_TYPE && aceType != ACCESS_DENIED_ACE_TYPE) |
|
207 return null; |
|
208 AclEntryType type; |
|
209 if (aceType == ACCESS_ALLOWED_ACE_TYPE) { |
|
210 type = AclEntryType.ALLOW; |
|
211 } else { |
|
212 type = AclEntryType.DENY; |
|
213 } |
|
214 |
|
215 // map flags |
|
216 byte aceFlags = unsafe.getByte(aceAddress + OFFSETOF_FLAGS); |
|
217 Set<AclEntryFlag> flags = new HashSet<AclEntryFlag>(); |
|
218 if ((aceFlags & OBJECT_INHERIT_ACE) != 0) |
|
219 flags.add(AclEntryFlag.FILE_INHERIT); |
|
220 if ((aceFlags & CONTAINER_INHERIT_ACE) != 0) |
|
221 flags.add(AclEntryFlag.DIRECTORY_INHERIT); |
|
222 if ((aceFlags & NO_PROPAGATE_INHERIT_ACE) != 0) |
|
223 flags.add(AclEntryFlag.NO_PROPAGATE_INHERIT); |
|
224 if ((aceFlags & INHERIT_ONLY_ACE) != 0) |
|
225 flags.add(AclEntryFlag.INHERIT_ONLY); |
|
226 |
|
227 // map access mask |
|
228 int mask = unsafe.getInt(aceAddress + OFFSETOF_ACCESS_MASK); |
|
229 Set<AclEntryPermission> perms = new HashSet<AclEntryPermission>(); |
|
230 if ((mask & FILE_READ_DATA) > 0) |
|
231 perms.add(AclEntryPermission.READ_DATA); |
|
232 if ((mask & FILE_WRITE_DATA) > 0) |
|
233 perms.add(AclEntryPermission.WRITE_DATA); |
|
234 if ((mask & FILE_APPEND_DATA ) > 0) |
|
235 perms.add(AclEntryPermission.APPEND_DATA); |
|
236 if ((mask & FILE_READ_EA) > 0) |
|
237 perms.add(AclEntryPermission.READ_NAMED_ATTRS); |
|
238 if ((mask & FILE_WRITE_EA) > 0) |
|
239 perms.add(AclEntryPermission.WRITE_NAMED_ATTRS); |
|
240 if ((mask & FILE_EXECUTE) > 0) |
|
241 perms.add(AclEntryPermission.EXECUTE); |
|
242 if ((mask & FILE_DELETE_CHILD ) > 0) |
|
243 perms.add(AclEntryPermission.DELETE_CHILD); |
|
244 if ((mask & FILE_READ_ATTRIBUTES) > 0) |
|
245 perms.add(AclEntryPermission.READ_ATTRIBUTES); |
|
246 if ((mask & FILE_WRITE_ATTRIBUTES) > 0) |
|
247 perms.add(AclEntryPermission.WRITE_ATTRIBUTES); |
|
248 if ((mask & DELETE) > 0) |
|
249 perms.add(AclEntryPermission.DELETE); |
|
250 if ((mask & READ_CONTROL) > 0) |
|
251 perms.add(AclEntryPermission.READ_ACL); |
|
252 if ((mask & WRITE_DAC) > 0) |
|
253 perms.add(AclEntryPermission.WRITE_ACL); |
|
254 if ((mask & WRITE_OWNER) > 0) |
|
255 perms.add(AclEntryPermission.WRITE_OWNER); |
|
256 if ((mask & SYNCHRONIZE) > 0) |
|
257 perms.add(AclEntryPermission.SYNCHRONIZE); |
|
258 |
|
259 // lookup SID to create UserPrincipal |
|
260 long sidAddress = aceAddress + OFFSETOF_SID; |
|
261 UserPrincipal user = WindowsUserPrincipals.fromSid(sidAddress); |
|
262 |
|
263 return AclEntry.newBuilder() |
|
264 .setType(type) |
|
265 .setPrincipal(user) |
|
266 .setFlags(flags).setPermissions(perms).build(); |
|
267 } |
|
268 |
|
269 // encode NFSv4 AclEntry as Windows ACE to given ACL |
|
270 private static void encode(AclEntry ace, long sidAddress, long aclAddress) |
|
271 throws WindowsException |
|
272 { |
|
273 // ignore non-allow/deny entries for now |
|
274 if (ace.type() != AclEntryType.ALLOW && ace.type() != AclEntryType.DENY) |
|
275 return; |
|
276 boolean allow = (ace.type() == AclEntryType.ALLOW); |
|
277 |
|
278 // map access mask |
|
279 Set<AclEntryPermission> aceMask = ace.permissions(); |
|
280 int mask = 0; |
|
281 if (aceMask.contains(AclEntryPermission.READ_DATA)) |
|
282 mask |= FILE_READ_DATA; |
|
283 if (aceMask.contains(AclEntryPermission.WRITE_DATA)) |
|
284 mask |= FILE_WRITE_DATA; |
|
285 if (aceMask.contains(AclEntryPermission.APPEND_DATA)) |
|
286 mask |= FILE_APPEND_DATA; |
|
287 if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS)) |
|
288 mask |= FILE_READ_EA; |
|
289 if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS)) |
|
290 mask |= FILE_WRITE_EA; |
|
291 if (aceMask.contains(AclEntryPermission.EXECUTE)) |
|
292 mask |= FILE_EXECUTE; |
|
293 if (aceMask.contains(AclEntryPermission.DELETE_CHILD)) |
|
294 mask |= FILE_DELETE_CHILD; |
|
295 if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES)) |
|
296 mask |= FILE_READ_ATTRIBUTES; |
|
297 if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES)) |
|
298 mask |= FILE_WRITE_ATTRIBUTES; |
|
299 if (aceMask.contains(AclEntryPermission.DELETE)) |
|
300 mask |= DELETE; |
|
301 if (aceMask.contains(AclEntryPermission.READ_ACL)) |
|
302 mask |= READ_CONTROL; |
|
303 if (aceMask.contains(AclEntryPermission.WRITE_ACL)) |
|
304 mask |= WRITE_DAC; |
|
305 if (aceMask.contains(AclEntryPermission.WRITE_OWNER)) |
|
306 mask |= WRITE_OWNER; |
|
307 if (aceMask.contains(AclEntryPermission.SYNCHRONIZE)) |
|
308 mask |= SYNCHRONIZE; |
|
309 |
|
310 // map flags |
|
311 Set<AclEntryFlag> aceFlags = ace.flags(); |
|
312 byte flags = 0; |
|
313 if (aceFlags.contains(AclEntryFlag.FILE_INHERIT)) |
|
314 flags |= OBJECT_INHERIT_ACE; |
|
315 if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT)) |
|
316 flags |= CONTAINER_INHERIT_ACE; |
|
317 if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT)) |
|
318 flags |= NO_PROPAGATE_INHERIT_ACE; |
|
319 if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY)) |
|
320 flags |= INHERIT_ONLY_ACE; |
|
321 |
|
322 if (allow) { |
|
323 AddAccessAllowedAceEx(aclAddress, flags, mask, sidAddress); |
|
324 } else { |
|
325 AddAccessDeniedAceEx(aclAddress, flags, mask, sidAddress); |
|
326 } |
|
327 } |
|
328 |
|
329 /** |
|
330 * Creates a security descriptor with a DACL representing the given ACL. |
|
331 */ |
|
332 static WindowsSecurityDescriptor create(List<AclEntry> acl) |
|
333 throws IOException |
|
334 { |
|
335 return new WindowsSecurityDescriptor(acl); |
|
336 } |
|
337 |
|
338 /** |
|
339 * Processes the array of attributes looking for the attribute "acl:acl". |
|
340 * Returns security descriptor representing the ACL or the "null" security |
|
341 * descriptor if the attribute is not in the array. |
|
342 */ |
|
343 @SuppressWarnings("unchecked") |
|
344 static WindowsSecurityDescriptor fromAttribute(FileAttribute<?>... attrs) |
|
345 throws IOException |
|
346 { |
|
347 WindowsSecurityDescriptor sd = NULL_DESCRIPTOR; |
|
348 for (FileAttribute<?> attr: attrs) { |
|
349 // if more than one ACL specified then last one wins |
|
350 if (sd != NULL_DESCRIPTOR) |
|
351 sd.release(); |
|
352 if (attr == null) |
|
353 throw new NullPointerException(); |
|
354 if (attr.name().equals("acl:acl")) { |
|
355 List<AclEntry> acl = (List<AclEntry>)attr.value(); |
|
356 sd = new WindowsSecurityDescriptor(acl); |
|
357 } else { |
|
358 throw new UnsupportedOperationException("'" + attr.name() + |
|
359 "' not supported as initial attribute"); |
|
360 } |
|
361 } |
|
362 return sd; |
|
363 } |
|
364 |
|
365 /** |
|
366 * Extracts DACL from security descriptor. |
|
367 */ |
|
368 static List<AclEntry> getAcl(long pSecurityDescriptor) throws IOException { |
|
369 // get address of DACL |
|
370 long aclAddress = GetSecurityDescriptorDacl(pSecurityDescriptor); |
|
371 |
|
372 // get ACE count |
|
373 int aceCount = 0; |
|
374 if (aclAddress == 0L) { |
|
375 // no ACEs |
|
376 aceCount = 0; |
|
377 } else { |
|
378 AclInformation aclInfo = GetAclInformation(aclAddress); |
|
379 aceCount = aclInfo.aceCount(); |
|
380 } |
|
381 ArrayList<AclEntry> result = new ArrayList<AclEntry>(aceCount); |
|
382 |
|
383 // decode each of the ACEs to AclEntry objects |
|
384 for (int i=0; i<aceCount; i++) { |
|
385 long aceAddress = GetAce(aclAddress, i); |
|
386 AclEntry entry = decode(aceAddress); |
|
387 if (entry != null) |
|
388 result.add(entry); |
|
389 } |
|
390 return result; |
|
391 } |
|
392 } |