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 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 = 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 }