Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java
32288 views
/*1* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.fs;2627import java.nio.file.ProviderMismatchException;28import java.nio.file.attribute.*;29import java.util.*;30import java.io.IOException;31import sun.misc.Unsafe;3233import static sun.nio.fs.WindowsNativeDispatcher.*;34import static sun.nio.fs.WindowsConstants.*;3536/**37* A SecurityDescriptor for use when setting a file's ACL or creating a file38* with an initial ACL.39*/4041class WindowsSecurityDescriptor {42private static final Unsafe unsafe = Unsafe.getUnsafe();4344/**45* typedef struct _ACL {46* BYTE AclRevision;47* BYTE Sbz1;48* WORD AclSize;49* WORD AceCount;50* WORD Sbz2;51* } ACL;52*53* typedef struct _ACE_HEADER {54* BYTE AceType;55* BYTE AceFlags;56* WORD AceSize;57* } ACE_HEADER;58*59* typedef struct _ACCESS_ALLOWED_ACE {60* ACE_HEADER Header;61* ACCESS_MASK Mask;62* DWORD SidStart;63* } ACCESS_ALLOWED_ACE;64*65* typedef struct _ACCESS_DENIED_ACE {66* ACE_HEADER Header;67* ACCESS_MASK Mask;68* DWORD SidStart;69* } ACCESS_DENIED_ACE;70*71* typedef struct _SECURITY_DESCRIPTOR {72* BYTE Revision;73* BYTE Sbz1;74* SECURITY_DESCRIPTOR_CONTROL Control;75* PSID Owner;76* PSID Group;77* PACL Sacl;78* PACL Dacl;79* } SECURITY_DESCRIPTOR;80*/81private static final short SIZEOF_ACL = 8;82private static final short SIZEOF_ACCESS_ALLOWED_ACE = 12;83private static final short SIZEOF_ACCESS_DENIED_ACE = 12;84private static final short SIZEOF_SECURITY_DESCRIPTOR = 20;8586private static final short OFFSETOF_TYPE = 0;87private static final short OFFSETOF_FLAGS = 1;88private static final short OFFSETOF_ACCESS_MASK = 4;89private static final short OFFSETOF_SID = 8;9091// null security descriptor92private static final WindowsSecurityDescriptor NULL_DESCRIPTOR =93new WindowsSecurityDescriptor();9495// native resources96private final List<Long> sidList;97private final NativeBuffer aclBuffer, sdBuffer;9899/**100* Creates the "null" SecurityDescriptor101*/102private WindowsSecurityDescriptor() {103this.sidList = null;104this.aclBuffer = null;105this.sdBuffer = null;106}107108/**109* Creates a SecurityDescriptor from the given ACL110*/111private WindowsSecurityDescriptor(List<AclEntry> acl) throws IOException {112boolean initialized = false;113114// SECURITY: need to copy list in case size changes during processing115acl = new ArrayList<AclEntry>(acl);116117// list of SIDs118sidList = new ArrayList<Long>(acl.size());119try {120// initial size of ACL121int size = SIZEOF_ACL;122123// get the SID for each entry124for (AclEntry entry: acl) {125UserPrincipal user = entry.principal();126if (!(user instanceof WindowsUserPrincipals.User))127throw new ProviderMismatchException();128String sidString = ((WindowsUserPrincipals.User)user).sidString();129try {130long pSid = ConvertStringSidToSid(sidString);131sidList.add(pSid);132133// increase size to allow for entry134size += GetLengthSid(pSid) +135Math.max(SIZEOF_ACCESS_ALLOWED_ACE, SIZEOF_ACCESS_DENIED_ACE);136137} catch (WindowsException x) {138throw new IOException("Failed to get SID for " + user.getName()139+ ": " + x.errorString());140}141}142143// allocate memory for the ACL144aclBuffer = NativeBuffers.getNativeBuffer(size);145sdBuffer = NativeBuffers.getNativeBuffer(SIZEOF_SECURITY_DESCRIPTOR);146147InitializeAcl(aclBuffer.address(), size);148149// Add entry ACE to the ACL150int i = 0;151while (i < acl.size()) {152AclEntry entry = acl.get(i);153long pSid = sidList.get(i);154try {155encode(entry, pSid, aclBuffer.address());156} catch (WindowsException x) {157throw new IOException("Failed to encode ACE: " +158x.errorString());159}160i++;161}162163// initialize security descriptor and set DACL164InitializeSecurityDescriptor(sdBuffer.address());165SetSecurityDescriptorDacl(sdBuffer.address(), aclBuffer.address());166initialized = true;167} catch (WindowsException x) {168throw new IOException(x.getMessage());169} finally {170// release resources if not completely initialized171if (!initialized)172release();173}174}175176/**177* Releases memory associated with SecurityDescriptor178*/179void release() {180if (sdBuffer != null)181sdBuffer.release();182if (aclBuffer != null)183aclBuffer.release();184if (sidList != null) {185// release memory for SIDs186for (Long sid: sidList) {187LocalFree(sid);188}189}190}191192/**193* Returns address of SecurityDescriptor194*/195long address() {196return (sdBuffer == null) ? 0L : sdBuffer.address();197}198199// decode Windows ACE to NFSv4 AclEntry200private static AclEntry decode(long aceAddress)201throws IOException202{203// map type204byte aceType = unsafe.getByte(aceAddress + OFFSETOF_TYPE);205if (aceType != ACCESS_ALLOWED_ACE_TYPE && aceType != ACCESS_DENIED_ACE_TYPE)206return null;207AclEntryType type;208if (aceType == ACCESS_ALLOWED_ACE_TYPE) {209type = AclEntryType.ALLOW;210} else {211type = AclEntryType.DENY;212}213214// map flags215byte aceFlags = unsafe.getByte(aceAddress + OFFSETOF_FLAGS);216Set<AclEntryFlag> flags = EnumSet.noneOf(AclEntryFlag.class);217if ((aceFlags & OBJECT_INHERIT_ACE) != 0)218flags.add(AclEntryFlag.FILE_INHERIT);219if ((aceFlags & CONTAINER_INHERIT_ACE) != 0)220flags.add(AclEntryFlag.DIRECTORY_INHERIT);221if ((aceFlags & NO_PROPAGATE_INHERIT_ACE) != 0)222flags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);223if ((aceFlags & INHERIT_ONLY_ACE) != 0)224flags.add(AclEntryFlag.INHERIT_ONLY);225226// map access mask227int mask = unsafe.getInt(aceAddress + OFFSETOF_ACCESS_MASK);228Set<AclEntryPermission> perms = EnumSet.noneOf(AclEntryPermission.class);229if ((mask & FILE_READ_DATA) > 0)230perms.add(AclEntryPermission.READ_DATA);231if ((mask & FILE_WRITE_DATA) > 0)232perms.add(AclEntryPermission.WRITE_DATA);233if ((mask & FILE_APPEND_DATA ) > 0)234perms.add(AclEntryPermission.APPEND_DATA);235if ((mask & FILE_READ_EA) > 0)236perms.add(AclEntryPermission.READ_NAMED_ATTRS);237if ((mask & FILE_WRITE_EA) > 0)238perms.add(AclEntryPermission.WRITE_NAMED_ATTRS);239if ((mask & FILE_EXECUTE) > 0)240perms.add(AclEntryPermission.EXECUTE);241if ((mask & FILE_DELETE_CHILD ) > 0)242perms.add(AclEntryPermission.DELETE_CHILD);243if ((mask & FILE_READ_ATTRIBUTES) > 0)244perms.add(AclEntryPermission.READ_ATTRIBUTES);245if ((mask & FILE_WRITE_ATTRIBUTES) > 0)246perms.add(AclEntryPermission.WRITE_ATTRIBUTES);247if ((mask & DELETE) > 0)248perms.add(AclEntryPermission.DELETE);249if ((mask & READ_CONTROL) > 0)250perms.add(AclEntryPermission.READ_ACL);251if ((mask & WRITE_DAC) > 0)252perms.add(AclEntryPermission.WRITE_ACL);253if ((mask & WRITE_OWNER) > 0)254perms.add(AclEntryPermission.WRITE_OWNER);255if ((mask & SYNCHRONIZE) > 0)256perms.add(AclEntryPermission.SYNCHRONIZE);257258// lookup SID to create UserPrincipal259long sidAddress = aceAddress + OFFSETOF_SID;260UserPrincipal user = WindowsUserPrincipals.fromSid(sidAddress);261262return AclEntry.newBuilder()263.setType(type)264.setPrincipal(user)265.setFlags(flags).setPermissions(perms).build();266}267268// encode NFSv4 AclEntry as Windows ACE to given ACL269private static void encode(AclEntry ace, long sidAddress, long aclAddress)270throws WindowsException271{272// ignore non-allow/deny entries for now273if (ace.type() != AclEntryType.ALLOW && ace.type() != AclEntryType.DENY)274return;275boolean allow = (ace.type() == AclEntryType.ALLOW);276277// map access mask278Set<AclEntryPermission> aceMask = ace.permissions();279int mask = 0;280if (aceMask.contains(AclEntryPermission.READ_DATA))281mask |= FILE_READ_DATA;282if (aceMask.contains(AclEntryPermission.WRITE_DATA))283mask |= FILE_WRITE_DATA;284if (aceMask.contains(AclEntryPermission.APPEND_DATA))285mask |= FILE_APPEND_DATA;286if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS))287mask |= FILE_READ_EA;288if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS))289mask |= FILE_WRITE_EA;290if (aceMask.contains(AclEntryPermission.EXECUTE))291mask |= FILE_EXECUTE;292if (aceMask.contains(AclEntryPermission.DELETE_CHILD))293mask |= FILE_DELETE_CHILD;294if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES))295mask |= FILE_READ_ATTRIBUTES;296if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES))297mask |= FILE_WRITE_ATTRIBUTES;298if (aceMask.contains(AclEntryPermission.DELETE))299mask |= DELETE;300if (aceMask.contains(AclEntryPermission.READ_ACL))301mask |= READ_CONTROL;302if (aceMask.contains(AclEntryPermission.WRITE_ACL))303mask |= WRITE_DAC;304if (aceMask.contains(AclEntryPermission.WRITE_OWNER))305mask |= WRITE_OWNER;306if (aceMask.contains(AclEntryPermission.SYNCHRONIZE))307mask |= SYNCHRONIZE;308309// map flags310Set<AclEntryFlag> aceFlags = ace.flags();311byte flags = 0;312if (aceFlags.contains(AclEntryFlag.FILE_INHERIT))313flags |= OBJECT_INHERIT_ACE;314if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT))315flags |= CONTAINER_INHERIT_ACE;316if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT))317flags |= NO_PROPAGATE_INHERIT_ACE;318if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY))319flags |= INHERIT_ONLY_ACE;320321if (allow) {322AddAccessAllowedAceEx(aclAddress, flags, mask, sidAddress);323} else {324AddAccessDeniedAceEx(aclAddress, flags, mask, sidAddress);325}326}327328/**329* Creates a security descriptor with a DACL representing the given ACL.330*/331static WindowsSecurityDescriptor create(List<AclEntry> acl)332throws IOException333{334return new WindowsSecurityDescriptor(acl);335}336337/**338* Processes the array of attributes looking for the attribute "acl:acl".339* Returns security descriptor representing the ACL or the "null" security340* descriptor if the attribute is not in the array.341*/342@SuppressWarnings("unchecked")343static WindowsSecurityDescriptor fromAttribute(FileAttribute<?>... attrs)344throws IOException345{346WindowsSecurityDescriptor sd = NULL_DESCRIPTOR;347for (FileAttribute<?> attr: attrs) {348// if more than one ACL specified then last one wins349if (sd != NULL_DESCRIPTOR)350sd.release();351if (attr == null)352throw new NullPointerException();353if (attr.name().equals("acl:acl")) {354List<AclEntry> acl = (List<AclEntry>)attr.value();355sd = new WindowsSecurityDescriptor(acl);356} else {357throw new UnsupportedOperationException("'" + attr.name() +358"' not supported as initial attribute");359}360}361return sd;362}363364/**365* Extracts DACL from security descriptor.366*/367static List<AclEntry> getAcl(long pSecurityDescriptor) throws IOException {368// get address of DACL369long aclAddress = GetSecurityDescriptorDacl(pSecurityDescriptor);370371// get ACE count372int aceCount = 0;373if (aclAddress == 0L) {374// no ACEs375aceCount = 0;376} else {377AclInformation aclInfo = GetAclInformation(aclAddress);378aceCount = aclInfo.aceCount();379}380ArrayList<AclEntry> result = new ArrayList<>(aceCount);381382// decode each of the ACEs to AclEntry objects383for (int i=0; i<aceCount; i++) {384long aceAddress = GetAce(aclAddress, i);385AclEntry entry = decode(aceAddress);386if (entry != null)387result.add(entry);388}389return result;390}391}392393394