diff options
Diffstat (limited to 'netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java')
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java | 255 |
1 files changed, 251 insertions, 4 deletions
diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java index 5a74e11..9b93a2d 100644 --- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java +++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java @@ -17,10 +17,13 @@ package net.sourceforge.jnlp.runtime; import static net.sourceforge.jnlp.runtime.Translator.R; +import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; @@ -46,11 +49,14 @@ import java.util.Vector; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; - +import net.sourceforge.jnlp.AppletDesc; +import net.sourceforge.jnlp.ApplicationDesc; import net.sourceforge.jnlp.DownloadOptions; import net.sourceforge.jnlp.ExtensionDesc; import net.sourceforge.jnlp.JARDesc; import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.JNLPMatcher; +import net.sourceforge.jnlp.JNLPMatcherException; import net.sourceforge.jnlp.LaunchException; import net.sourceforge.jnlp.ParseException; import net.sourceforge.jnlp.PluginBridge; @@ -81,6 +87,13 @@ public class JNLPClassLoader extends URLClassLoader { // extension classes too so that main file classes can load // resources in an extension. + /** Signed JNLP File and Template */ + final public static String TEMPLATE = "JNLP-INF/APPLICATION_TEMPLATE.JNLP"; + final public static String APPLICATION = "JNLP-INF/APPLICATION.JNLP"; + + /** True if the application has a signed JNLP File */ + private boolean isSignedJNLP = false; + /** map from JNLPFile url to shared classloader */ private static Map<String, JNLPClassLoader> urlToLoader = new HashMap<String, JNLPClassLoader>(); // never garbage collected! @@ -153,6 +166,10 @@ public class JNLPClassLoader extends URLClassLoader { /** Loader for codebase (which is a path, rather than a file) */ private CodeBaseClassLoader codeBaseLoader; + + /** True if the jar with the main class has been found + * */ + private boolean foundMainJar= false; /** * Create a new JNLPClassLoader from the specified file. @@ -460,6 +477,26 @@ public class JNLPClassLoader extends URLClassLoader { !SecurityDialogs.showNotAllSignedWarningDialog(file)) throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo")); + + // Check for main class in the downloaded jars, and check/verify signed JNLP fill + checkForMain(initialJars); + + // If jar with main class was not found, check available resources + while (!foundMainJar && available != null && available.size() != 0) + addNextResource(); + + // If jar with main class was not found and there are no more + // available jars, throw a LaunchException + if (!foundMainJar + && (available == null || available.size() == 0)) + throw new LaunchException(file, null, R("LSFatal"), + R("LCClient"), R("LCantDetermineMainClass"), + R("LCantDetermineMainClassInfo")); + + // If main jar was found, but a signed JNLP file was not located + if (!isSignedJNLP && foundMainJar) + file.setSignedJNLPAsMissing(); + //user does not trust this publisher if (!js.getAlreadyTrustPublisher()) { checkTrustWithUser(js); @@ -518,10 +555,205 @@ public class JNLPClassLoader extends URLClassLoader { System.err.println(mfe.getMessage()); } } - activateJars(initialJars); } + + /*** + * Checks for the jar that contains the main class. If the main class was + * found, it checks to see if the jar is signed and whether it contains a + * signed JNLP file + * + * @param jars Jars that are checked to see if they contain the main class + * @throws LaunchException Thrown if the signed JNLP file, within the main jar, fails to be verified or does not match + */ + private void checkForMain(List<JARDesc> jars) throws LaunchException { + + Object obj = file.getLaunchInfo(); + String mainClass; + + if (obj instanceof ApplicationDesc) { + ApplicationDesc ad = (ApplicationDesc) file.getLaunchInfo(); + mainClass = ad.getMainClass(); + } else if (obj instanceof AppletDesc) { + AppletDesc ad = (AppletDesc) file.getLaunchInfo(); + mainClass = ad.getMainClass(); + } else + return; + + for (int i = 0; i < jars.size(); i++) { + + try { + File localFile = tracker + .getCacheFile(jars.get(i).getLocation()); + + if (localFile == null) + throw new NullPointerException( + "Could not locate jar file, returned null"); + + JarFile jarFile = new JarFile(localFile); + Enumeration<JarEntry> entries = jarFile.entries(); + JarEntry je; + + while (entries.hasMoreElements()) { + je = entries.nextElement(); + String jeName = je.getName().replaceAll("/", "."); + + if (!jeName.startsWith(mainClass + "$Inner") + && (jeName.startsWith(mainClass) && jeName.endsWith(".class"))) { + foundMainJar = true; + verifySignedJNLP(jars.get(i), jarFile); + break; + } + } + } catch (IOException e) { + /* + * After this exception is caught, it is escaped. This will skip + * the jarFile that may have thrown this exception and move on + * to the next jarFile (if there are any) + */ + } + } + } + /** + * Is called by checkForMain() to check if the jar file is signed and if it + * contains a signed JNLP file. + * + * @param jarDesc JARDesc of jar + * @param jarFile the jar file + * @throws LaunchException thrown if the signed JNLP file, within the main jar, fails to be verified or does not match + */ + private void verifySignedJNLP(JARDesc jarDesc, JarFile jarFile) + throws LaunchException { + + JarSigner signer = new JarSigner(); + List<JARDesc> desc = new ArrayList<JARDesc>(); + desc.add(jarDesc); + + // Initialize streams + InputStream inStream = null; + InputStreamReader inputReader = null; + FileReader fr = null; + InputStreamReader jnlpReader = null; + + try { + signer.verifyJars(desc, tracker); + + if (signer.allJarsSigned()) { // If the jar is signed + + Enumeration<JarEntry> entries = jarFile.entries(); + JarEntry je; + + while (entries.hasMoreElements()) { + je = entries.nextElement(); + String jeName = je.getName().toUpperCase(); + + if (jeName.equals(TEMPLATE) || jeName.equals(APPLICATION)) { + + if (JNLPRuntime.isDebug()) + System.err.println("Creating Jar InputStream from JarEntry"); + + inStream = jarFile.getInputStream(je); + inputReader = new InputStreamReader(inStream); + + if (JNLPRuntime.isDebug()) + System.err.println("Creating File InputStream from lauching JNLP file"); + + JNLPFile jnlp = this.getJNLPFile(); + URL url = jnlp.getFileLocation(); + File jn = null; + + // If the file is on the local file system, use original path, otherwise find cached file + if (url.getProtocol().toLowerCase().equals("file")) + jn = new File(url.getPath()); + else + jn = CacheUtil.getCacheFile(url, null); + + fr = new FileReader(jn); + jnlpReader = fr; + + // Initialize JNLPMatcher class + JNLPMatcher matcher; + + if (jeName.equals(APPLICATION)) { // If signed application was found + if (JNLPRuntime.isDebug()) + System.err.println("APPLICATION.JNLP has been located within signed JAR. Starting verfication..."); + + matcher = new JNLPMatcher(inputReader, jnlpReader, false); + } else { // Otherwise template was found + if (JNLPRuntime.isDebug()) + System.err.println("APPLICATION_TEMPLATE.JNLP has been located within signed JAR. Starting verfication..."); + + matcher = new JNLPMatcher(inputReader, jnlpReader, + true); + } + + // If signed JNLP file does not matches launching JNLP file, throw JNLPMatcherException + if (!matcher.isMatch()) + throw new JNLPMatcherException("Signed Application did not match launching JNLP File"); + + this.isSignedJNLP = true; + if (JNLPRuntime.isDebug()) + System.err.println("Signed Application Verification Successful"); + + break; + } + } + } + } catch (JNLPMatcherException e) { + + /* + * Throws LaunchException if signed JNLP file fails to be verified + * or fails to match the launching JNLP file + */ + + throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), + R("LSignedJNLPFileDidNotMatch"), R(e.getMessage())); + + /* + * Throwing this exception will fail to initialize the application + * resulting in the termination of the application + */ + + } catch (Exception e) { + + if (JNLPRuntime.isDebug()) + e.printStackTrace(System.err); + + /* + * After this exception is caught, it is escaped. If an exception is + * thrown while handling the jar file, (mainly for + * JarSigner.verifyJars) it assumes the jar file is unsigned and + * skip the check for a signed JNLP file + */ + + } finally { + + //Close all streams + closeStream(inStream); + closeStream(inputReader); + closeStream(fr); + closeStream(jnlpReader); + } + + if (JNLPRuntime.isDebug()) + System.err.println("Ending check for signed JNLP file..."); + } + + /*** + * Closes a stream + * + * @param stream the stream that will be closed + */ + private void closeStream (Closeable stream) { + if (stream != null) + try { + stream.close(); + } catch (Exception e) { + e.printStackTrace(System.err); + } + } + private void checkTrustWithUser(JarSigner js) throws LaunchException { if (!js.getRootInCacerts()) { //root cert is not in cacerts boolean b = SecurityDialogs.showCertWarningDialog( @@ -1154,7 +1386,20 @@ public class JNLPClassLoader extends URLClassLoader { // add resources until found while (true) { - JNLPClassLoader addedTo = addNextResource(); + JNLPClassLoader addedTo = null; + + try { + addedTo = addNextResource(); + } catch (LaunchException e) { + + /* + * This method will never handle any search for the main class + * [It is handled in initializeResources()]. Therefore, this + * exception will never be thrown here and is escaped + */ + + throw new IllegalStateException(e); + } if (addedTo == null) throw new ClassNotFoundException(name); @@ -1245,8 +1490,9 @@ public class JNLPClassLoader extends URLClassLoader { * no more resources to add, the method returns immediately. * * @return the classloader that resources were added to, or null + * @throws LaunchException Thrown if the signed JNLP file, within the main jar, fails to be verified or does not match */ - protected JNLPClassLoader addNextResource() { + protected JNLPClassLoader addNextResource() throws LaunchException { if (available.size() == 0) { for (int i = 1; i < loaders.length; i++) { JNLPClassLoader result = loaders[i].addNextResource(); @@ -1262,6 +1508,7 @@ public class JNLPClassLoader extends URLClassLoader { jars.add(available.get(0)); fillInPartJars(jars); + checkForMain(jars); activateJars(jars); return this; |