1 /* 2 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 jdk.internal.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 = EnumSet.noneOf(AclEntryFlag.class); 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 = EnumSet.noneOf(AclEntryPermission.class); 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<>(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 }