Mercurial > hg > icedtea8
changeset 1962:77ea95965bad
Security patches for netx+plugin.
2009-08-05 Lillian Angel <langel@redhat.com>
* plugin/icedtea/netscape/javascript/JSObject.java: Security patch
applied to disallow the ability to run unsigned code as
signed under some cases.
* plugin/icedtea/sun/applet/PluginAppletSecurityContext.java:
Likewise.
* netx/net/sourceforge/jnlp/SecurityDesc.java: Likewise.
* netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: Likewise.
* plugin/icedtea/netscape/javascript/JSObjectCreatePermission.java:
Likewise.
* netx/netscape/javascript/JSObjectCreatePermission.java: Likewise.
author | Andrew John Hughes <ahughes@redhat.com> |
---|---|
date | Wed, 05 Aug 2009 15:22:13 +0100 |
parents | adadd58eff31 |
children | a6ecfd52e2db |
files | ChangeLog netx/net/sourceforge/jnlp/SecurityDesc.java netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java netx/netscape/javascript/JSObjectCreatePermission.java plugin/icedtea/netscape/javascript/JSObject.java plugin/icedtea/netscape/javascript/JSObjectCreatePermission.java plugin/icedtea/sun/applet/PluginAppletSecurityContext.java |
diffstat | 7 files changed, 349 insertions(+), 169 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Wed Aug 05 15:02:51 2009 +0100 +++ b/ChangeLog Wed Aug 05 15:22:13 2009 +0100 @@ -1,3 +1,16 @@ +2009-08-05 Lillian Angel <langel@redhat.com> + + * plugin/icedtea/netscape/javascript/JSObject.java: Security patch + applied to disallow the ability to run unsigned code as + signed under some cases. + * plugin/icedtea/sun/applet/PluginAppletSecurityContext.java: + Likewise. + * netx/net/sourceforge/jnlp/SecurityDesc.java: Likewise. + * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: Likewise. + * plugin/icedtea/netscape/javascript/JSObjectCreatePermission.java: + Likewise. + * netx/netscape/javascript/JSObjectCreatePermission.java: Likewise. + 2009-08-04 Andrew John Hughes <ahughes@redhat.com> * Makefile.am:
--- a/netx/net/sourceforge/jnlp/SecurityDesc.java Wed Aug 05 15:02:51 2009 +0100 +++ b/netx/net/sourceforge/jnlp/SecurityDesc.java Wed Aug 05 15:22:13 2009 +0100 @@ -166,6 +166,30 @@ return permissions; } + + /** + * Returns a PermissionCollection containing the sandbox permissions + */ + public PermissionCollection getSandBoxPermissions() { + + Permissions permissions = new Permissions(); + + for (int i=0; i < sandboxPermissions.length; i++) + permissions.add(sandboxPermissions[i]); + + if (downloadHost != null) + permissions.add(new SocketPermission(downloadHost, + "connect, accept")); + + // properties + PropertyDesc props[] = file.getResources().getProperties(); + for (int i=0; i < props.length; i++) { + // should only allow jnlp.* properties if in sandbox? + permissions.add(new PropertyPermission(props[i].getKey(), "read,write")); + } + + return permissions; + } }
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java Wed Aug 05 15:02:51 2009 +0100 +++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java Wed Aug 05 15:22:13 2009 +0100 @@ -1,15 +1,15 @@ -// +// // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. -// +// // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@ -66,7 +66,7 @@ * security context when the classloader was created. * * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author - * @version $Revision: 1.20 $ + * @version $Revision: 1.20 $ */ public class JNLPClassLoader extends URLClassLoader { @@ -115,29 +115,29 @@ /** the security section */ private SecurityDesc security; - + /** Permissions granted by the user during runtime. */ private ArrayList<Permission> runtimePermissions = new ArrayList<Permission>(); /** all jars not yet part of classloader or active */ private List available = new ArrayList(); - /** all of the jar files that were verified */ - private ArrayList<String> verifiedJars = null; + /** all of the jar files that were verified */ + private ArrayList<String> verifiedJars = null; - /** all of the jar files that were not verified */ - private ArrayList<String> unverifiedJars = null; + /** all of the jar files that were not verified */ + private ArrayList<String> unverifiedJars = null; - /** the jarsigner tool to verify our jars */ - private JarSigner js = null; + /** the jarsigner tool to verify our jars */ + private JarSigner js = null; + + private boolean signing = false; - private boolean signing = false; - - /** ArrayList containing jar indexes for various jars available to this classloader */ - private ArrayList<JarIndex> jarIndexes = new ArrayList<JarIndex>(); - - /** File entries in the jar files available to this classloader */ - private TreeSet jarEntries = new TreeSet(); + /** ArrayList containing jar indexes for various jars available to this classloader */ + private ArrayList<JarIndex> jarIndexes = new ArrayList<JarIndex>(); + + /** File entries in the jar files available to this classloader */ + private TreeSet jarEntries = new TreeSet(); /** * Create a new JNLPClassLoader from the specified file. @@ -167,41 +167,41 @@ } private void setSecurity() { - /** - * When we're trying to load an applet, file.getSecurity() will return - * null since there is no jnlp file to specify permissions. We - * determine security settings here, after trying to verify jars. - */ - if (file instanceof PluginBridge) { - if (signing == true) { - this.security = new SecurityDesc(file, - SecurityDesc.ALL_PERMISSIONS, - file.getCodeBase().getHost()); - } else { - this.security = new SecurityDesc(file, - SecurityDesc.SANDBOX_PERMISSIONS, - file.getCodeBase().getHost()); - } - } else { //regular jnlp file - - /** - * If the application is signed, then we set the SecurityDesc to the - * <security> tag in the jnlp file. Note that if an application is - * signed, but there is no <security> tag in the jnlp file, the - * application will get sandbox permissions. - * If the application is unsigned, we ignore the <security> tag and - * use a sandbox instead. - */ - if (signing == true) { - this.security = file.getSecurity(); - } else { - this.security = new SecurityDesc(file, - SecurityDesc.SANDBOX_PERMISSIONS, - file.getCodeBase().getHost()); - } - } + /** + * When we're trying to load an applet, file.getSecurity() will return + * null since there is no jnlp file to specify permissions. We + * determine security settings here, after trying to verify jars. + */ + if (file instanceof PluginBridge) { + if (signing == true) { + this.security = new SecurityDesc(file, + SecurityDesc.ALL_PERMISSIONS, + file.getCodeBase().getHost()); + } else { + this.security = new SecurityDesc(file, + SecurityDesc.SANDBOX_PERMISSIONS, + file.getCodeBase().getHost()); + } + } else { //regular jnlp file + + /** + * If the application is signed, then we set the SecurityDesc to the + * <security> tag in the jnlp file. Note that if an application is + * signed, but there is no <security> tag in the jnlp file, the + * application will get sandbox permissions. + * If the application is unsigned, we ignore the <security> tag and + * use a sandbox instead. + */ + if (signing == true) { + this.security = file.getSecurity(); + } else { + this.security = new SecurityDesc(file, + SecurityDesc.SANDBOX_PERMISSIONS, + file.getCodeBase().getHost()); + } + } } - + /** * Returns a JNLP classloader for the specified JNLP file. * @@ -215,12 +215,12 @@ if (location != null) loader = (JNLPClassLoader) urlToLoader.get(location); - try { - if (loader == null) - loader = new JNLPClassLoader(file, policy); - } catch (LaunchException e) { - throw e; - } + try { + if (loader == null) + loader = new JNLPClassLoader(file, policy); + } catch (LaunchException e) { + throw e; + } if (file.getInformation().isSharingAllowed()) urlToLoader.put(location, loader); @@ -230,7 +230,7 @@ /** * Returns a JNLP classloader for the JNLP file at the specified - * location. + * location. * * @param location the file's location * @param version the file's version @@ -256,17 +256,17 @@ loaderList.add(this); - //if (ext != null) { - for (int i=0; i < ext.length; i++) { - try { - JNLPClassLoader loader = getInstance(ext[i].getLocation(), ext[i].getVersion(), updatePolicy); - loaderList.add(loader); - } - catch (Exception ex) { - ex.printStackTrace(); - } - } - //} + //if (ext != null) { + for (int i=0; i < ext.length; i++) { + try { + JNLPClassLoader loader = getInstance(ext[i].getLocation(), ext[i].getVersion(), updatePolicy); + loaderList.add(loader); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + //} loaders = (JNLPClassLoader[]) loaderList.toArray(new JNLPClassLoader[ loaderList.size()]); } @@ -283,10 +283,10 @@ jars[i].getVersion()); if (JNLPRuntime.isDebug()) { - if (p == null) - System.out.println("Unable to add permission for " + jars[i].getLocation()); - else - System.out.println("Permission added: " + p.toString()); + if (p == null) + System.out.println("Unable to add permission for " + jars[i].getLocation()); + else + System.out.println("Permission added: " + p.toString()); } if (p != null) resourcePermissions.add(p); @@ -299,14 +299,14 @@ */ void initializeResources() throws LaunchException { JARDesc jars[] = resources.getJARs(); - if (jars == null || jars.length == 0) - return; - /* - if (jars == null || jars.length == 0) { - throw new LaunchException(null, null, R("LSFatal"), - R("LCInit"), R("LFatalVerification"), "No jars!"); - } - */ + if (jars == null || jars.length == 0) + return; + /* + if (jars == null || jars.length == 0) { + throw new LaunchException(null, null, R("LSFatal"), + R("LCInit"), R("LFatalVerification"), "No jars!"); + } + */ List initialJars = new ArrayList(); for (int i=0; i < jars.length; i++) { @@ -317,7 +317,7 @@ initialJars.add(jars[i]); // regardless of part tracker.addResource(jars[i].getLocation(), - jars[i].getVersion(), + jars[i].getVersion(), jars[i].isCacheable() ? JNLPRuntime.getDefaultUpdatePolicy() : UpdatePolicy.FORCE ); } @@ -325,42 +325,42 @@ if (strict) fillInPartJars(initialJars); // add in each initial part's lazy jars - if (JNLPRuntime.isVerifying()) { + if (JNLPRuntime.isVerifying()) { - JarSigner js; - waitForJars(initialJars); //download the jars first. + JarSigner js; + waitForJars(initialJars); //download the jars first. - try { - js = verifyJars(initialJars); - } catch (Exception e) { - //we caught an Exception from the JarSigner class. - //Note: one of these exceptions could be from not being able - //to read the cacerts or trusted.certs files. - e.printStackTrace(); - throw new LaunchException(null, null, R("LSFatal"), - R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo")); - } + try { + js = verifyJars(initialJars); + } catch (Exception e) { + //we caught an Exception from the JarSigner class. + //Note: one of these exceptions could be from not being able + //to read the cacerts or trusted.certs files. + e.printStackTrace(); + throw new LaunchException(null, null, R("LSFatal"), + R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo")); + } - //Case when at least one jar has some signing - if (js.anyJarsSigned()){ - signing = true; + //Case when at least one jar has some signing + if (js.anyJarsSigned()){ + signing = true; - //user does not trust this publisher - if (!js.getAlreadyTrustPublisher()) { - checkTrustWithUser(js); - } else { - /** - * If the user trusts this publisher (i.e. the publisher's certificate - * is in the user's trusted.certs file), we do not show any dialogs. - */ - } - } else { + //user does not trust this publisher + if (!js.getAlreadyTrustPublisher()) { + checkTrustWithUser(js); + } else { + /** + * If the user trusts this publisher (i.e. the publisher's certificate + * is in the user's trusted.certs file), we do not show any dialogs. + */ + } + } else { - signing = false; - //otherwise this jar is simply unsigned -- make sure to ask - //for permission on certain actions - } - } + signing = false; + //otherwise this jar is simply unsigned -- make sure to ask + //for permission on certain actions + } + } activateJars(initialJars); } @@ -370,7 +370,7 @@ boolean b = SecurityWarningDialog.showCertWarningDialog( SecurityWarningDialog.AccessType.UNVERIFIED, file, js); if (!b) - throw new LaunchException(null, null, R("LSFatal"), + throw new LaunchException(null, null, R("LSFatal"), R("LCLaunching"), R("LNotVerified"), ""); } else if (js.getRootInCacerts()) { //root cert is in cacerts boolean b = false; @@ -435,11 +435,29 @@ // access w/o security dialog once we actually check certificates. // copy security permissions from SecurityDesc element - if (security != null) { - Enumeration e = security.getPermissions().elements(); - while (e.hasMoreElements()) - result.add((Permission) e.nextElement()); - } + if (security != null) { + // Security desc. is used only to track security settings for the + // application. However, an application may comprise of multiple + // jars, and as such, security must be evaluated on a per jar basis. + + // set default perms + PermissionCollection permissions = security.getSandBoxPermissions(); + + // If more than default is needed, evaluate based on codesource + if (security.getSecurityType().equals(SecurityDesc.ALL_PERMISSIONS) || + security.getSecurityType().equals(SecurityDesc.J2EE_PERMISSIONS)) { + + if (cs.getCodeSigners() != null) { + permissions = security.getPermissions(); + } + } + + Enumeration<Permission> e = permissions.elements(); + while (e.hasMoreElements()) + result.add(e.nextElement()); + } + + // add in permission to read the cached JAR files for (int i=0; i < resourcePermissions.size(); i++) @@ -447,15 +465,15 @@ // add in the permissions that the user granted. for (int i=0; i < runtimePermissions.size(); i++) - result.add(runtimePermissions.get(i)); + result.add(runtimePermissions.get(i)); return result; } protected void addPermission(Permission p) { - runtimePermissions.add(p); + runtimePermissions.add(p); } - + /** * Adds to the specified list of JARS any other JARs that need * to be loaded at the same time as the JARs specified (ie, are @@ -501,25 +519,25 @@ URL location = jar.getLocation(); // non-cacheable, use source location if (localFile != null) { location = localFile.toURL(); // cached file - - // This is really not the best way.. but we need some way for - // PluginAppletViewer::getCachedImageRef() to check if the image - // is available locally, and it cannot use getResources() because - // that prefetches the resource, which confuses MediaTracker.waitForAll() - // which does a wait(), waiting for notification (presumably + + // This is really not the best way.. but we need some way for + // PluginAppletViewer::getCachedImageRef() to check if the image + // is available locally, and it cannot use getResources() because + // that prefetches the resource, which confuses MediaTracker.waitForAll() + // which does a wait(), waiting for notification (presumably // thrown after a resource is fetched). This bug manifests itself // particularly when using The FileManager applet from Webmin. - + JarFile jarFile = new JarFile(localFile); Enumeration e = jarFile.entries(); while (e.hasMoreElements()) { - + JarEntry je = (JarEntry) e.nextElement(); - - // another jar in my jar? it is more likely than you think + + // another jar in my jar? it is more likely than you think if (je.getName().endsWith(".jar")) { - // We need to extract that jar so that it can be loaded - // (inline loading with "jar:..!/..." path will not work + // We need to extract that jar so that it can be loaded + // (inline loading with "jar:..!/..." path will not work // with standard classloader methods) String extractedJarLocation = localFile.getParent() + "/" + je.getName(); @@ -564,7 +582,7 @@ addURL(location); - // there is currently no mechanism to cache files per + // there is currently no mechanism to cache files per // instance.. so only index cached files if (localFile != null) { JarIndex index = JarIndex.getJarIndex(new JarFile(localFile.getAbsolutePath()), null); @@ -636,11 +654,11 @@ * calls. */ protected File getNativeDir() { - nativeDir = new File(System.getProperty("java.io.tmpdir") - + File.separator + "netx-native-" + nativeDir = new File(System.getProperty("java.io.tmpdir") + + File.separator + "netx-native-" + (new Random().nextInt() & 0xFFFF)); - if (!nativeDir.mkdirs()) + if (!nativeDir.mkdirs()) return null; else return nativeDir; @@ -703,16 +721,16 @@ } /** - * Verifies code signing of jars to be used. - * - * @param jars the jars to be verified. - */ - private JarSigner verifyJars(List<JARDesc> jars) throws Exception { - - js = new JarSigner(); - js.verifyJars(jars, tracker); - return js; - } + * Verifies code signing of jars to be used. + * + * @param jars the jars to be verified. + */ + private JarSigner verifyJars(List<JARDesc> jars) throws Exception { + + js = new JarSigner(); + js.verifyJars(jars, tracker); + return js; + } /** * Find the loaded class in this loader or any of its extension loaders. @@ -765,7 +783,7 @@ // Not found in external loader either. As a last resort, look in any available indexes - // Currently this loads jars directly from the site. We cannot cache it because this + // Currently this loads jars directly from the site. We cannot cache it because this // call is initiated from within the applet, which does not have disk read/write permissions for (JarIndex index: jarIndexes) { LinkedList<String> jarList = index.get(name.replace('.', '/')); @@ -783,7 +801,7 @@ available.add(desc); tracker.addResource(desc.getLocation(), - desc.getVersion(), + desc.getVersion(), JNLPRuntime.getDefaultUpdatePolicy() ); @@ -807,7 +825,7 @@ } - // If it still fails, let it error out + // If it still fails, let it error out result = loadClassExt(name); } } @@ -891,7 +909,7 @@ if (loaders[i] == this) e = super.findResources(name); - else + else e = loaders[i].findResources(name); while (e.hasMoreElements()) @@ -900,10 +918,10 @@ return resources.elements(); } - + /** * Returns if the specified resource is available locally from a cached jar - * + * * @param s The name of the resource * @return Whether or not the resource is available locally */ @@ -949,8 +967,8 @@ fillInPartJars(jars); - - activateJars(jars); + + activateJars(jars); return this; } @@ -979,13 +997,13 @@ return file.getFileLocation().toString(); } - public boolean getSigning() { - return signing; - } + public boolean getSigning() { + return signing; + } - protected SecurityDesc getSecurity() { - return security; - } + protected SecurityDesc getSecurity() { + return security; + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/netx/netscape/javascript/JSObjectCreatePermission.java Wed Aug 05 15:22:13 2009 +0100 @@ -0,0 +1,47 @@ +/* JSObjectCreatePermission.java + Copyright (C) 2009 Red Hat + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +IcedTea is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package netscape.javascript; + +import java.security.BasicPermission; + + +public class JSObjectCreatePermission extends BasicPermission { + public JSObjectCreatePermission() { + super("JSObjectCreate"); + } +}
--- a/plugin/icedtea/netscape/javascript/JSObject.java Wed Aug 05 15:02:51 2009 +0100 +++ b/plugin/icedtea/netscape/javascript/JSObject.java Wed Aug 05 15:22:13 2009 +0100 @@ -47,6 +47,10 @@ package netscape.javascript; import java.applet.Applet; +import java.security.AccessControlContext; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.BasicPermission; import sun.applet.PluginAppletViewer; import sun.applet.PluginDebug; @@ -102,13 +106,37 @@ /** * it is illegal to construct a JSObject manually */ - // FIXME: make private! public JSObject(int jsobj_addr) { - PluginDebug.debug ("JSObject int CONSTRUCTOR"); - internal = jsobj_addr; + this((long) jsobj_addr); } public JSObject(long jsobj_addr) { + + // See if the caller has permission + + try { + AccessController.getContext().checkPermission(new JSObjectCreatePermission()); + } catch (AccessControlException ace) { + + // If not, only caller with JSObject.getWindow on the stack may + // make this call unprivileged. + + // Although this check is inefficient, it should happen only once + // during applet init, so we look the other way + + StackTraceElement[] stack = Thread.currentThread().getStackTrace(); + boolean mayProceed = false; + + for (int i=0; i < stack.length; i++) { + if (stack[i].getClassName().equals("netscape.javascript.JSObject") && + stack[i].getMethodName().equals("getWindow")) { + mayProceed = true; + } + } + + if (!mayProceed) throw ace; + } + PluginDebug.debug ("JSObject long CONSTRUCTOR"); internal = jsobj_addr; } @@ -234,7 +262,7 @@ internal = ((PluginAppletViewer) applet.getAppletContext()).getWindow(); PluginDebug.debug ("GOT IT: " + internal); - return new JSObject(internal); + return new JSObject((long) internal); } @@ -259,5 +287,4 @@ return false; } - }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/icedtea/netscape/javascript/JSObjectCreatePermission.java Wed Aug 05 15:22:13 2009 +0100 @@ -0,0 +1,47 @@ +/* JSObjectCreatePermission.java + Copyright (C) 2009 Red Hat + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +IcedTea is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package netscape.javascript; + +import java.security.BasicPermission; + + +public class JSObjectCreatePermission extends BasicPermission { + public JSObjectCreatePermission() { + super("JSObjectCreate"); + } +}
--- a/plugin/icedtea/sun/applet/PluginAppletSecurityContext.java Wed Aug 05 15:02:51 2009 +0100 +++ b/plugin/icedtea/sun/applet/PluginAppletSecurityContext.java Wed Aug 05 15:22:13 2009 +0100 @@ -58,6 +58,7 @@ import java.util.List; import net.sourceforge.jnlp.runtime.JNLPRuntime; +import netscape.javascript.JSObjectCreatePermission; @@ -1285,12 +1286,15 @@ CodeSource cs = new CodeSource((URL) null, (java.security.cert.Certificate [])null); - if (src != null) { + if (src != null && src.length() > 0) { try { cs = new CodeSource(new URL(src + "/"), (java.security.cert.Certificate[]) null); } catch (MalformedURLException mfue) { // do nothing } + } else { + JSObjectCreatePermission perm = new JSObjectCreatePermission(); + grantedPermissions.add(perm); } ProtectionDomain pd = new ProtectionDomain(cs, grantedPermissions, null, null);