changeset 55:dcd3d1728ff4

create files with reduced permissions when possible 2010-11-24 Omair Majid <omajid@redhat.com> * netx/net/sourceforge/jnlp/util/FileUtils.java (createRestrictedDirectory): New method. Creates a directory with reduced permissions. (createRestrictedFile(File,boolean)): New method. Creates a file with reduced permissions. (createRestrictedFile(File,boolean,boolean): New method. Creates a file or a directory with reduced permissions. * netx/net/sourceforge/jnlp/Launcher.java (markNetxRunning): Do not grant unnecessary file permissions. * netx/net/sourceforge/jnlp/runtime/Boot.java: Remove umask from help message. * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java (activateNative): Create file with proper permissions. (getNativeDir): Create directory with proper permissions. * netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java (initializeStreams): Create files with proper permissions. * netx/net/sourceforge/jnlp/security/CertWarningPane.java (CheckBoxListener.actionPerformed): Likewise. * netx/net/sourceforge/jnlp/security/KeyStores.java (createKeyStoreFromFile): Likewise. * netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java (ImportButtonListener.actionPerformed): Likewise. (RemoveButtonListener.actionPerformed): Likewise. * netx/net/sourceforge/jnlp/services/SingleInstanceLock.java (createWithPort): Likewise. (getLockFile): Likewise. * netx/net/sourceforge/jnlp/services/XExtendedService.java (openFile): Likewise. * netx/net/sourceforge/jnlp/services/XPersistenceService.java (create): Likewise. * netx/net/sourceforge/jnlp/util/XDesktopEntry.java (installDesktopLauncher): Likewise. * netx/net/sourceforge/jnlp/resources/Messages.properties: Add CantCreateFile, RCantCreateDir and RCantRename. Remove BNoBase and BOUmask.
author Omair Majid <omajid@redhat.com>
date Wed, 24 Nov 2010 15:47:50 -0500
parents 5267f9104d5f
children 918f525349b3
files ChangeLog netx/net/sourceforge/jnlp/Launcher.java netx/net/sourceforge/jnlp/resources/Messages.properties netx/net/sourceforge/jnlp/runtime/Boot.java netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java netx/net/sourceforge/jnlp/security/CertWarningPane.java netx/net/sourceforge/jnlp/security/KeyStores.java netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java netx/net/sourceforge/jnlp/services/SingleInstanceLock.java netx/net/sourceforge/jnlp/services/XFileSaveService.java netx/net/sourceforge/jnlp/services/XPersistenceService.java netx/net/sourceforge/jnlp/util/FileUtils.java netx/net/sourceforge/jnlp/util/XDesktopEntry.java
diffstat 14 files changed, 184 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Nov 24 15:22:03 2010 -0500
+++ b/ChangeLog	Wed Nov 24 15:47:50 2010 -0500
@@ -1,3 +1,41 @@
+2010-11-24  Omair Majid  <omajid@redhat.com>
+
+	* netx/net/sourceforge/jnlp/util/FileUtils.java
+	(createRestrictedDirectory): New method. Creates a directory with reduced
+	permissions.
+	(createRestrictedFile(File,boolean)): New method. Creates a file with reduced
+	permissions.
+	(createRestrictedFile(File,boolean,boolean): New method. Creates a file or
+	a directory with reduced permissions.
+	* netx/net/sourceforge/jnlp/Launcher.java
+	(markNetxRunning): Do not grant unnecessary file permissions.
+	* netx/net/sourceforge/jnlp/runtime/Boot.java: Remove umask from
+	help message.
+	* netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
+	(activateNative): Create file with proper permissions.
+	(getNativeDir): Create directory with proper permissions.
+	* netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java
+	(initializeStreams): Create files with proper permissions.
+	* netx/net/sourceforge/jnlp/security/CertWarningPane.java
+	(CheckBoxListener.actionPerformed): Likewise.
+	* netx/net/sourceforge/jnlp/security/KeyStores.java
+	(createKeyStoreFromFile): Likewise.
+	* netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java
+	(ImportButtonListener.actionPerformed): Likewise.
+	(RemoveButtonListener.actionPerformed): Likewise.
+	* netx/net/sourceforge/jnlp/services/SingleInstanceLock.java
+	(createWithPort): Likewise.
+	(getLockFile): Likewise.
+	* netx/net/sourceforge/jnlp/services/XExtendedService.java
+	(openFile): Likewise.
+	* netx/net/sourceforge/jnlp/services/XPersistenceService.java
+	(create): Likewise.
+	* netx/net/sourceforge/jnlp/util/XDesktopEntry.java
+	(installDesktopLauncher): Likewise.
+	* netx/net/sourceforge/jnlp/resources/Messages.properties: Add
+	CantCreateFile, RCantCreateDir and RCantRename. Remove BNoBase and
+	BOUmask.
+
 2010-11-24  Deepak Bhole <dbhole@redhat.com>
 
 	Fix PR593: Increment of invalidated iterator in IcedTeaPluginUtils (patch
--- a/netx/net/sourceforge/jnlp/Launcher.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/Launcher.java	Wed Nov 24 15:47:50 2010 -0500
@@ -48,6 +48,7 @@
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
 import net.sourceforge.jnlp.services.InstanceExistsException;
 import net.sourceforge.jnlp.services.ServiceUtil;
+import net.sourceforge.jnlp.util.FileUtils;
 import net.sourceforge.jnlp.util.Reflect;
 
 import javax.swing.SwingUtilities;
@@ -727,8 +728,9 @@
 
             File netxRunningFile = new File(JNLPRuntime.getConfiguration()
                     .getProperty(DeploymentConfiguration.KEY_USER_NETX_RUNNING_FILE));
-            netxRunningFile.getParentFile().mkdirs();
-            if (netxRunningFile.createNewFile()) {
+            if (!netxRunningFile.exists()) {
+                netxRunningFile.getParentFile().mkdirs();
+                FileUtils.createRestrictedFile(netxRunningFile, true);
                 FileOutputStream fos = new FileOutputStream(netxRunningFile);
                 try {
                     fos.write(message.getBytes());
@@ -737,14 +739,6 @@
                 }
             }
 
-            if (!netxRunningFile.isFile()) {
-                if (JNLPRuntime.isDebug()) {
-                    System.err.println("Unable to create instance file");
-                }
-                fileLock = null;
-                return;
-            }
-
             FileInputStream is = new FileInputStream(netxRunningFile);
             FileChannel channel = is.getChannel();
             fileLock = channel.tryLock(0, Long.MAX_VALUE, true);
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties	Wed Nov 24 15:47:50 2010 -0500
@@ -124,11 +124,13 @@
 BBadProp=Incorrect property format {0} (should be key=value)
 BBadParam=Incorrect parameter format {0} (should be name=value)
 BNoDir=Directory {0} does not exist.
-BNoBase=No base directory (contains cache and other data)
 RNoResource=Missing Resource: {0}
 RShutdown=This exception to prevent shutdown of JVM, but the process has been terminated.
 RExitTaken=Exit class already set and caller is not exit class.
 RCantReplaceSM=Changing the SecurityManager is not allowed.
+RCantCreateFile=Cant create file {0}
+RCantCreateDir=Cant create directory {0}
+RCantRename=Cant rename {0} to {0}
 RDenyStopped=Stopped applications have no permissions.
 RExitNoApp=Can not exit the JVM because the current application cannot be determined.
 RNoLockDir=Unable to create locks directory ({0})
@@ -152,7 +154,6 @@
 BOHeadless  = Disables download window, other UIs.
 BOStrict    = Enables strict checking of JNLP file format.
 BOViewer    = Shows the trusted certificate viewer.
-BOUmask     = Sets the umask for files created by an application.
 BXnofork    = Do not create another JVM.
 BXclearcache= Clean the JNLP application cache.
 BOHelp      = Print this message and exit.
--- a/netx/net/sourceforge/jnlp/runtime/Boot.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/runtime/Boot.java	Wed Nov 24 15:47:50 2010 -0500
@@ -105,7 +105,6 @@
         + "  -noupdate             "+R("BONoupdate")+"\n"
         + "  -headless             "+R("BOHeadless")+"\n"
         + "  -strict               "+R("BOStrict")+"\n"
-        + "  -umask=value          "+R("BOUmask")+"\n"
         + "  -Xnofork              "+R("BXnofork")+"\n"
         + "  -Xclearcache          "+R("BXclearcache")+"\n"
         + "  -help                 "+R("BOHelp")+"\n";
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Wed Nov 24 15:47:50 2010 -0500
@@ -815,7 +815,9 @@
                     nativeDir = getNativeDir();
 
                 File outFile = new File(nativeDir, name);
-
+                if (!outFile.isFile()) {
+                    FileUtils.createRestrictedFile(outFile, true);
+                }
                 CacheUtil.streamCopy(jarFile.getInputStream(e),
                                      new FileOutputStream(outFile));
 
@@ -837,12 +839,18 @@
                              + File.separator + "netx-native-"
                              + (new Random().nextInt() & 0xFFFF));
 
-        if (!nativeDir.mkdirs())
+        File parent = nativeDir.getParentFile();
+        if (!parent.isDirectory() && !parent.mkdirs()) {
             return null;
-        else {
+        }
+
+        try {
+            FileUtils.createRestrictedDirectory(nativeDir);
             // add this new native directory to the search path
             addNativeDirectory(nativeDir);
             return nativeDir;
+        } catch (IOException e) {
+            return null;
         }
     }
 
--- a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Wed Nov 24 15:47:50 2010 -0500
@@ -268,12 +268,15 @@
                 .getProperty(DeploymentConfiguration.KEY_ENABLE_LOGGING));
         if (redirectStreams || enableLogging) {
             String logDir = config.getProperty(DeploymentConfiguration.KEY_USER_LOG_DIR);
-            File errFile = new File(logDir, JNLPRuntime.STDERR_FILE);
-            errFile.getParentFile().mkdirs();
-            File outFile = new File(logDir, JNLPRuntime.STDOUT_FILE);
-            outFile.getParentFile().mkdirs();
 
             try {
+                File errFile = new File(logDir, JNLPRuntime.STDERR_FILE);
+                errFile.getParentFile().mkdirs();
+                FileUtils.createRestrictedFile(errFile, true);
+                File outFile = new File(logDir, JNLPRuntime.STDOUT_FILE);
+                outFile.getParentFile().mkdirs();
+                FileUtils.createRestrictedFile(outFile, true);
+
                 if (redirectStreams) {
                     System.setErr(new PrintStream(new FileOutputStream(errFile)));
                     System.setOut(new PrintStream(new FileOutputStream(outFile)));
--- a/netx/net/sourceforge/jnlp/security/CertWarningPane.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/security/CertWarningPane.java	Wed Nov 24 15:47:50 2010 -0500
@@ -47,6 +47,7 @@
 import java.awt.GridLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.io.File;
 import java.io.FileOutputStream;
 import java.io.OutputStream;
 import java.security.KeyStore;
@@ -68,6 +69,7 @@
 import net.sourceforge.jnlp.security.KeyStores.Level;
 import net.sourceforge.jnlp.security.KeyStores.Type;
 import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
+import net.sourceforge.jnlp.util.FileUtils;
 
 /**
  * Provides the panel for using inside a SecurityWarningDialog. These dialogs are
@@ -246,7 +248,12 @@
                     KeyStore ks = KeyStores.getKeyStore(Level.USER, Type.CERTS);
                     X509Certificate c = (X509Certificate) parent.getJarSigner().getPublisher();
                     CertificateUtils.addToKeyStore(c, ks);
-                    OutputStream os = new FileOutputStream(KeyStores.getKeyStoreLocation(Level.USER, Type.CERTS));
+                    File keyStoreFile = new File(KeyStores.getKeyStoreLocation(Level.USER, Type.CERTS));
+                    if (!keyStoreFile.isFile()) {
+                        FileUtils.createRestrictedFile(keyStoreFile, true);
+                    }
+
+                    OutputStream os = new FileOutputStream(keyStoreFile);
                     ks.store(os, KeyStores.getPassword());
                     if (JNLPRuntime.isDebug()) {
                         System.out.println("certificate is now permanently trusted");
--- a/netx/net/sourceforge/jnlp/security/KeyStores.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/security/KeyStores.java	Wed Nov 24 15:47:50 2010 -0500
@@ -53,6 +53,7 @@
 import net.sourceforge.jnlp.runtime.DeploymentConfiguration;
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
 import net.sourceforge.jnlp.runtime.Translator;
+import net.sourceforge.jnlp.util.FileUtils;
 
 /**
  * The <code>KeyStores</code> class allows easily accessing the various KeyStores
@@ -339,6 +340,8 @@
                 if (!parent.isDirectory() && !parent.mkdirs()) {
                     throw new IOException("unable to create " + parent);
                 }
+                FileUtils.createRestrictedFile(file, true);
+
                 ks = KeyStore.getInstance(KEYSTORE_TYPE);
                 ks.load(null, password.toCharArray());
                 FileOutputStream fos = new FileOutputStream(file);
--- a/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java	Wed Nov 24 15:47:50 2010 -0500
@@ -45,6 +45,7 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
+import java.io.File;
 import java.io.FileOutputStream;
 import java.io.OutputStream;
 import java.io.PrintStream;
@@ -76,6 +77,7 @@
 import net.sourceforge.jnlp.security.SecurityUtil;
 import net.sourceforge.jnlp.security.SecurityWarningDialog;
 import net.sourceforge.jnlp.security.KeyStores.Level;
+import net.sourceforge.jnlp.util.FileUtils;
 
 public class CertificatePane extends JPanel {
 
@@ -361,8 +363,13 @@
                         try {
                                 KeyStore ks = keyStore;
                                 CertificateUtils.addToKeyStore(chooser.getSelectedFile(), ks);
-                                OutputStream os = new FileOutputStream(
-                                        KeyStores.getKeyStoreLocation(currentKeyStoreLevel, currentKeyStoreType));
+                                File keyStoreFile = new File(KeyStores
+                                        .getKeyStoreLocation(currentKeyStoreLevel, currentKeyStoreType));
+                                if (!keyStoreFile.isFile()) {
+                                    FileUtils.createRestrictedFile(keyStoreFile, true);
+                                }
+
+                                OutputStream os = new FileOutputStream(keyStoreFile);
                                 ks.store(os, KeyStores.getPassword());
                                 repopulateTables();
                         } catch (Exception ex) {
@@ -436,8 +443,12 @@
                                                         JOptionPane.YES_NO_OPTION);
                                         if (i == 0) {
                                                 keyStore.deleteEntry(alias);
-                                                FileOutputStream fos = new FileOutputStream(
-                                                        KeyStores.getKeyStoreLocation(currentKeyStoreLevel, currentKeyStoreType));
+                                                File keyStoreFile = new File(KeyStores
+                                                        .getKeyStoreLocation(currentKeyStoreLevel, currentKeyStoreType));
+                                                if (!keyStoreFile.isFile()) {
+                                                    FileUtils.createRestrictedFile(keyStoreFile, true);
+                                                }
+                                                FileOutputStream fos = new FileOutputStream(keyStoreFile);
                                                 keyStore.store(fos, KeyStores.getPassword());
                                                 fos.close();
                                         }
--- a/netx/net/sourceforge/jnlp/services/SingleInstanceLock.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/services/SingleInstanceLock.java	Wed Nov 24 15:47:50 2010 -0500
@@ -67,6 +67,7 @@
      */
     public void createWithPort(int localPort) throws IOException {
 
+        FileUtils.createRestrictedFile(lockFile, true);
         BufferedWriter lockFileWriter = new BufferedWriter(new FileWriter(lockFile, false));
         lockFileWriter.write(String.valueOf(localPort));
         lockFileWriter.newLine();
@@ -132,9 +133,17 @@
         File baseDir = new File(JNLPRuntime.getConfiguration()
                 .getProperty(DeploymentConfiguration.KEY_USER_LOCKS_DIR));
 
-        if (!baseDir.isDirectory() && !baseDir.mkdirs()) {
-            throw new RuntimeException(R("RNoLockDir", baseDir));
+        if (!baseDir.isDirectory()) {
+            if (!baseDir.getParentFile().isDirectory() && !baseDir.getParentFile().mkdirs()) {
+                throw new RuntimeException(R("RNoLockDir", baseDir));
+            }
+            try {
+                FileUtils.createRestrictedDirectory(baseDir);
+            } catch (IOException e) {
+                throw new RuntimeException(R("RNoLockDir", baseDir));
+            }
         }
+
         String lockFileName = getLockFileName();
         File applicationLockFile = new File(baseDir, lockFileName);
         return applicationLockFile;
--- a/netx/net/sourceforge/jnlp/services/XFileSaveService.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/services/XFileSaveService.java	Wed Nov 24 15:47:50 2010 -0500
@@ -44,6 +44,7 @@
 import javax.jnlp.*;
 
 import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
+import net.sourceforge.jnlp.util.FileUtils;
 
 import javax.swing.JFileChooser;
 import javax.swing.JOptionPane;
@@ -121,7 +122,7 @@
             if (!replace)
                 return;
         } else {
-            file.createNewFile();
+            FileUtils.createRestrictedFile(file, true);
         }
 
         if (file.canWrite()) {
--- a/netx/net/sourceforge/jnlp/services/XPersistenceService.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/services/XPersistenceService.java	Wed Nov 24 15:47:50 2010 -0500
@@ -26,6 +26,7 @@
 import net.sourceforge.jnlp.*;
 import net.sourceforge.jnlp.cache.*;
 import net.sourceforge.jnlp.runtime.*;
+import net.sourceforge.jnlp.util.FileUtils;
 
 /**
  * The BasicService JNLP service.
@@ -96,9 +97,11 @@
         File file = toCacheFile(location);
         file.getParentFile().mkdirs();
 
-        if (!file.createNewFile())
+        if (file.exists())
             throw new IOException("File already exists.");
 
+        FileUtils.createRestrictedFile(file, true);
+
         return maxsize;
     }
 
--- a/netx/net/sourceforge/jnlp/util/FileUtils.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/util/FileUtils.java	Wed Nov 24 15:47:50 2010 -0500
@@ -16,6 +16,8 @@
 
 package net.sourceforge.jnlp.util;
 
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
 import java.io.File;
 import java.io.IOException;
 
@@ -72,6 +74,79 @@
     }
 
     /**
+     * Creates a new directory with minimum permissions. The directory is not
+     * readable or writable by anyone other than the owner. The parent
+     * directories are not created; they must exist before this is called.
+     *
+     * @throws IOException
+     */
+    public static void createRestrictedDirectory(File directory) throws IOException {
+        createRestrictedFile(directory, true, true);
+    }
+
+    /**
+     * Creates a new file with minimum permissions. The file is not readable or
+     * writable by anyone other than the owner. If writeableByOnwer is false,
+     * even the owner can not write to it.
+     *
+     * @throws IOException
+     */
+    public static void createRestrictedFile(File file, boolean writableByOwner) throws IOException {
+        createRestrictedFile(file, false, writableByOwner);
+    }
+
+    /**
+     * Creates a new file or directory with minimum permissions. The file is not
+     * readable or writable by anyone other than the owner. If writeableByOnwer
+     * is false, even the owner can not write to it. If isDir is true, then the
+     * directory can be executed by the owner
+     *
+     * @throws IOException
+     */
+    private static void createRestrictedFile(File file, boolean isDir, boolean writableByOwner) throws IOException {
+
+        File tempFile = null;
+
+        tempFile = new File(file.getCanonicalPath() + ".temp");
+
+        if (isDir) {
+            if (!tempFile.mkdir()) {
+                throw new IOException(R("RCantCreateDir", tempFile));
+            }
+        } else {
+            if (!tempFile.createNewFile()) {
+                throw new IOException(R("RCantCreateFile", tempFile));
+            }
+        }
+
+        // remove all permissions
+        tempFile.setExecutable(false, false);
+        tempFile.setReadable(false, false);
+        tempFile.setWritable(false, false);
+
+        // allow owner to read
+        tempFile.setReadable(true, true);
+
+        // allow owner to write
+        if (writableByOwner) {
+            tempFile.setWritable(true, true);
+        }
+
+        // allow owner to enter directories
+        if (isDir) {
+            tempFile.setExecutable(true, true);
+        }
+
+        // rename this file. Unless the file is moved/renamed, any program that
+        // opened the file right after it was created might still be able to
+        // read the data.
+        if (!tempFile.renameTo(file)) {
+            throw new IOException(R("RCantRename", tempFile, file));
+        }
+
+    }
+
+    /**
      * Returns a String that is suitable for using in GUI elements for
      * displaying (long) paths to users.
      *
--- a/netx/net/sourceforge/jnlp/util/XDesktopEntry.java	Wed Nov 24 15:22:03 2010 -0500
+++ b/netx/net/sourceforge/jnlp/util/XDesktopEntry.java	Wed Nov 24 15:47:50 2010 -0500
@@ -158,6 +158,9 @@
             if (!shortcutFile.getParentFile().isDirectory() && !shortcutFile.getParentFile().mkdirs()) {
                 throw new IOException(shortcutFile.getParentFile().toString());
             }
+
+            FileUtils.createRestrictedFile(shortcutFile, true);
+
             /*
              * Write out a Java String (UTF-16) as a UTF-8 file
              */