jdk/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java
changeset 2057 3acf8e5e2ca0
child 5506 202f599c92aa
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     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 }