6590857: Drag & Drop arbitrary file copy
authordenis
Mon, 13 Apr 2009 21:42:44 +0400
changeset 2639 e7429e3a2529
parent 2478 a7e3157c1867
child 2640 643213b1a0a0
6590857: Drag & Drop arbitrary file copy Reviewed-by: uta
jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java
--- a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Mon Apr 13 15:22:12 2009 +0400
+++ b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Mon Apr 13 21:42:44 2009 +0400
@@ -65,10 +65,13 @@
 
 import java.rmi.MarshalledObject;
 
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -111,6 +114,8 @@
 import sun.awt.image.ImageRepresentation;
 import sun.awt.image.ToolkitImage;
 
+import java.io.FilePermission;
+
 
 /**
  * Provides a set of functions to be shared among the DataFlavor class and
@@ -1177,8 +1182,10 @@
             (String.class.equals(flavor.getRepresentationClass()) &&
              isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
 
+            String str = removeSuspectedData(flavor, contents, (String)obj);
+
             return translateTransferableString(
-                (String)obj,
+                str,
                 format);
 
         // Source data is a Reader. Convert to a String and recur. In the
@@ -1286,6 +1293,11 @@
                 throw new IOException("data translation failed");
             }
             final List list = (List)obj;
+
+            final ArrayList fileList = new ArrayList();
+
+            final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
+
             int nFiles = 0;
             for (int i = 0; i < list.size(); i++) {
                 Object o = list.get(i);
@@ -1293,17 +1305,18 @@
                     nFiles++;
                 }
             }
-            final String[] files = new String[nFiles];
 
             try {
                 AccessController.doPrivileged(new PrivilegedExceptionAction() {
                     public Object run() throws IOException {
-                        for (int i = 0, j = 0; i < list.size(); i++) {
-                            Object o = list.get(i);
-                            if (o instanceof File) {
-                                files[j++] = ((File)o).getCanonicalPath();
-                            } else if (o instanceof String) {
-                                files[j++] = (String)o;
+                        for (Object fileObject : list)
+                        {
+                            File file = castToFile(fileObject);
+                            if (null == System.getSecurityManager() ||
+                                !(isFileInWebstartedCache(file) ||
+                                isForbiddenToRead(file, userProtectionDomain)))
+                            {
+                                fileList.add(file.getCanonicalPath());
                             }
                         }
                         return null;
@@ -1313,10 +1326,11 @@
                 throw new IOException(pae.getMessage());
             }
 
-            for (int i = 0; i < files.length; i++) {
-                 byte[] bytes = files[i].getBytes();
-                 if (i != 0) bos.write(0);
-                 bos.write(bytes, 0, bytes.length);
+            for (int i = 0; i < fileList.size(); i++)
+            {
+                byte[] bytes = ((String)fileList.get(i)).getBytes();
+                if (i != 0) bos.write(0);
+                bos.write(bytes, 0, bytes.length);
             }
 
         // Source data is an InputStream. For arbitrary flavors, just grab the
@@ -1366,6 +1380,123 @@
         return ret;
     }
 
+    private String removeSuspectedData(DataFlavor flavor, final Transferable contents, final String str)
+            throws IOException
+    {
+        if (null == System.getSecurityManager()
+            || !flavor.isMimeTypeEqual("text/uri-list"))
+        {
+            return str;
+        }
+
+
+        String ret_val = "";
+        final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
+
+        try {
+            ret_val = (String) AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                    public Object run() {
+
+                        StringBuffer allowedFiles = new StringBuffer(str.length());
+                        String [] uriArray = str.split("(\\s)+");
+
+                        for (String fileName : uriArray)
+                        {
+                            File file = new File(fileName);
+                            if (file.exists() &&
+                                !(isFileInWebstartedCache(file) ||
+                                isForbiddenToRead(file, userProtectionDomain)))
+                            {
+
+                                if (0 != allowedFiles.length())
+                                {
+                                    allowedFiles.append("\\r\\n");
+                                }
+
+                                allowedFiles.append(fileName);
+                            }
+                        }
+
+                        return allowedFiles.toString();
+                    }
+                });
+        } catch (PrivilegedActionException pae) {
+            throw new IOException(pae.getMessage(), pae);
+        }
+
+        return ret_val;
+    }
+
+    private static ProtectionDomain getUserProtectionDomain(Transferable contents) {
+        return contents.getClass().getProtectionDomain();
+    }
+
+    private boolean isForbiddenToRead (File file, ProtectionDomain protectionDomain)
+    {
+        if (null == protectionDomain) {
+            return false;
+        }
+        try {
+            FilePermission filePermission =
+                    new FilePermission(file.getCanonicalPath(), "read, delete");
+            if (protectionDomain.implies(filePermission)) {
+                return false;
+            }
+        } catch (IOException e) {}
+
+        return true;
+    }
+
+    // It is important do not use user's successors
+    // of File class.
+    private File castToFile(Object fileObject) throws IOException {
+        String filePath = null;
+        if (fileObject instanceof File) {
+            filePath = ((File)fileObject).getCanonicalPath();
+        } else if (fileObject instanceof String) {
+           filePath = (String) fileObject;
+        }
+        return new File(filePath);
+    }
+
+    private final static String[] DEPLOYMENT_CACHE_PROPERTIES = {
+        "deployment.system.cachedir",
+        "deployment.user.cachedir",
+        "deployment.javaws.cachedir",
+        "deployment.javapi.cachedir"
+    };
+
+    private final static ArrayList <File> deploymentCacheDirectoryList =
+            new ArrayList<File>();
+
+    private static boolean isFileInWebstartedCache(File f) {
+
+        if (deploymentCacheDirectoryList.isEmpty()) {
+            for (String cacheDirectoryProperty : DEPLOYMENT_CACHE_PROPERTIES) {
+                String cacheDirectoryPath = System.getProperty(cacheDirectoryProperty);
+                if (cacheDirectoryPath != null) {
+                    try {
+                        File cacheDirectory = (new File(cacheDirectoryPath)).getCanonicalFile();
+                        if (cacheDirectory != null) {
+                            deploymentCacheDirectoryList.add(cacheDirectory);
+                        }
+                    } catch (IOException ioe) {}
+                }
+            }
+        }
+
+        for (File deploymentCacheDirectory : deploymentCacheDirectoryList) {
+            for (File dir = f; dir != null; dir = dir.getParentFile()) {
+                if (dir.equals(deploymentCacheDirectory)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+
     public Object translateBytes(byte[] bytes, DataFlavor flavor,
                                  long format, Transferable localeTransferable)
         throws IOException