From 3fc9df484c722ac350729e89930fe763183e7591 Mon Sep 17 00:00:00 2001 From: Kurt Zenker Date: Mon, 21 Mar 2005 10:38:47 +0000 Subject: [PATCH] INTEGRATION: CWS fwkpostbeta1 (1.4.96); FILE MERGED 2005/03/10 14:21:22 jl 1.4.96.3: #i41066# workaround for security functions, such as SecurityManager.currentClassLoader. They use in their implementation features of the new security mechanism. 2005/02/04 10:26:14 jl 1.4.96.2: #41066# use thread local storage for flag that signals recursion 2005/02/02 09:59:49 jl 1.4.96.1: #41066# changes to SecurityManager to allow Java components full permissions --- .../sun/star/lib/sandbox/SandboxSecurity.java | 948 ++++++++++++------ 1 file changed, 644 insertions(+), 304 deletions(-) diff --git a/sandbox/com/sun/star/lib/sandbox/SandboxSecurity.java b/sandbox/com/sun/star/lib/sandbox/SandboxSecurity.java index 89db32295726..8f1675662d40 100644 --- a/sandbox/com/sun/star/lib/sandbox/SandboxSecurity.java +++ b/sandbox/com/sun/star/lib/sandbox/SandboxSecurity.java @@ -2,9 +2,9 @@ * * $RCSfile: SandboxSecurity.java,v $ * - * $Revision: 1.4 $ + * $Revision: 1.5 $ * - * last change: $Author: jl $ $Date: 2002-10-16 10:36:47 $ + * last change: $Author: kz $ $Date: 2005-03-21 11:38:47 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -71,7 +71,6 @@ import java.util.StringTokenizer; import java.util.Vector; import java.util.Hashtable; import java.security.*; - import sun.security.provider.*; /** @@ -96,6 +95,11 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage String writeACL[]; int networkMode; boolean bCheckSecurity; + RecursionCounter InCheck = new RecursionCounter(); + RecursionCounter InIsSecureLoader = new RecursionCounter(); + RecursionCounter InInClassLoader = new RecursionCounter(); + RecursionCounter InClassLoaderDepth = new RecursionCounter(); + java.security.AllPermission allPerm = new java.security.AllPermission(); // where we look for identities IdentityScope scope; @@ -191,27 +195,40 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage // /** // * True if called indirectly from an untrusted applet. // */ - boolean inApplet() { - return inClassLoader(); + synchronized boolean inApplet() { + boolean ret = false; + try { + InCheck.acquire(); + ret = inClassLoader(); + } finally { + InCheck.release(); + } + return ret; } /** * The only variable that currently affects whether an applet can * perform certain operations is the host it came from. */ - public Object getSecurityContext() { - ClassLoader loader = currentClassLoader(); + public synchronized Object getSecurityContext() { + Object ret = null; + try { + InCheck.acquire(); + ClassLoader loader = currentClassLoader(); - if (loader == null) { - return null; - } else - if (loader instanceof ClassContextImpl) { - ClassContext appletLoader = (ClassContextImpl)loader; - return appletLoader.getBase(); - } else { - throw(new SandboxSecurityException("getsecuritycontext.unknown")); -// return null; + if (loader != null) { + if (loader instanceof ClassContextImpl) { + ClassContext appletLoader = (ClassContextImpl)loader; + ret = appletLoader.getBase(); + } else { + throw(new SandboxSecurityException("getsecuritycontext.unknown")); + } + } } + finally { + InCheck.release(); + } + return ret; } /** @@ -220,9 +237,14 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * checkClassLoaderOperation or somesuch. */ public synchronized void checkCreateClassLoader() { - if( bCheckSecurity && !isSecureLoader() ) { - if (classLoaderDepth() == 2) - throw(new SandboxSecurityException("checkcreateclassloader")); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if (classLoaderDepth() == 2) + throw(new SandboxSecurityException("checkcreateclassloader")); + } + } finally { + InCheck.release(); } } @@ -231,26 +253,40 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * group. This will return false if there is no current class * loader. */ - protected boolean inThreadGroup(ThreadGroup g) { - ClassLoader loader = currentClassLoader(); + protected synchronized boolean inThreadGroup(ThreadGroup g) { + boolean ret = false; + try { + InCheck.acquire(); + ClassLoader loader = currentClassLoader(); - /* If this class wasn't loaded by an AppletClassLoader, we have - not eay of telling, for now. */ + /* If this class wasn't loaded by an AppletClassLoader, we have + not eay of telling, for now. */ - if (loader instanceof ClassContextImpl) { - ClassContext appletLoader = (ClassContextImpl)loader; - ThreadGroup appletGroup = appletLoader.getThreadGroup(); - return appletGroup.parentOf(g); + if (loader instanceof ClassContextImpl) { + ClassContext appletLoader = (ClassContextImpl)loader; + ThreadGroup appletGroup = appletLoader.getThreadGroup(); + ret = appletGroup.parentOf(g); + } + } finally { + InCheck.release(); } - return false; + return ret; } /** * Returns true of the threadgroup of thread is in the applet's * own threadgroup. */ - protected boolean inThreadGroup(Thread thread) { - return inThreadGroup(thread.getThreadGroup()); + protected synchronized boolean inThreadGroup(Thread thread) { + boolean ret = false; + try { + InCheck.acquire(); + ret = inThreadGroup(thread.getThreadGroup()); + } + finally { + InCheck.release(); + } + return ret; } /** @@ -258,10 +294,15 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * applet thread groups. */ public synchronized void checkAccess(Thread t) { - if( bCheckSecurity && !isSecureLoader() ) { - if (classLoaderDepth()==3 && (! inThreadGroup(t))) { - throw(new SandboxSecurityException("checkaccess.thread")); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if (classLoaderDepth()==3 && (! inThreadGroup(t))) { + throw(new SandboxSecurityException("checkaccess.thread")); + } } + } finally { + InCheck.release(); } } @@ -270,24 +311,35 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * applet thread groups. */ public synchronized void checkAccess(ThreadGroup g) { - if( bCheckSecurity && !isSecureLoader() ) { - if (classLoaderDepth() == 4 && (! inThreadGroup(g))) { - throw(new SandboxSecurityException("checkaccess.threadgroup", g.toString())); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if (classLoaderDepth() == 4 && (! inThreadGroup(g))) { + throw(new SandboxSecurityException("checkaccess.threadgroup", g.toString())); + } } + } finally { + InCheck.release(); } + } /** * Applets are not allowed to exit the VM. */ public synchronized void checkExit(int status) { - if( bNoExit ) { - throw(new SandboxSecurityException("checkexit", String.valueOf(status))); - } - if( bCheckSecurity && !isSecureLoader() ) { - if( inApplet() ) { + try { + InCheck.acquire(); + if( bNoExit ) { throw(new SandboxSecurityException("checkexit", String.valueOf(status))); } + if( bCheckSecurity && !isSecureLoader() ) { + if( inApplet() ) { + throw(new SandboxSecurityException("checkexit", String.valueOf(status))); + } + } + } finally { + InCheck.release(); } } @@ -295,10 +347,15 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * Applets are not allowed to fork processes. */ public synchronized void checkExec(String cmd) { - if( bCheckSecurity && !isSecureLoader()) { - if (inApplet()) { - throw(new SandboxSecurityException("checkexec", cmd)); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader()) { + if (inApplet()) { + throw(new SandboxSecurityException("checkexec", cmd)); + } } + } finally { + InCheck.release(); } } @@ -306,14 +363,19 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * Applets are not allowed to link dynamic libraries. */ public synchronized void checkLink(String lib) { - if( bCheckSecurity && !isSecureLoader() ) { - switch (classLoaderDepth()) { - case 2: // Runtime.load - case 3: // System.loadLibrary + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + switch (classLoaderDepth()) { + case 2: // Runtime.load + case 3: // System.loadLibrary throw(new SandboxSecurityException("checklink", lib)); - default: - break; + default: + break; + } } + } finally { + InCheck.release(); } } @@ -322,10 +384,15 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * list, only properties explicitly labeled as accessible to applets. */ public synchronized void checkPropertiesAccess() { - if( bCheckSecurity && !isSecureLoader() ) { - if (classLoaderDepth() == 2) { - throw(new SandboxSecurityException("checkpropsaccess")); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if (classLoaderDepth() == 2) { + throw(new SandboxSecurityException("checkpropsaccess")); + } } + } finally { + InCheck.release(); } } @@ -336,14 +403,19 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * applets only if java.home.applet is true. */ public synchronized void checkPropertyAccess(String key) { - if( bCheckSecurity && !isSecureLoader() ) { - if (classLoaderDepth() == 2) { - String prop = System.getProperty(key + ".applet"); - boolean allow = new Boolean(prop).booleanValue(); - if ( !allow ) { - throw(new SandboxSecurityException("checkpropsaccess.key", prop)); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if (classLoaderDepth() == 2) { + String prop = System.getProperty(key + ".applet"); + boolean allow = new Boolean(prop).booleanValue(); + if ( !allow ) { + throw(new SandboxSecurityException("checkpropsaccess.key", prop)); + } } } + } finally { + InCheck.release(); } } @@ -402,74 +474,93 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * Check if an applet can read a particular file. */ public synchronized void checkRead(String file) { - if( bCheckSecurity && !isSecureLoader() ) { - ClassLoader loader = currentClassLoader(); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + ClassLoader loader = currentClassLoader(); - /* If no class loader, it's a system class. */ - if (loader == null) - return; - - /* If not an AppletClassLoader, we don't know what to do */ - if (! (loader instanceof ClassContextImpl)) - throw(new SandboxSecurityException("checkread.unknown", file)); - ClassContext appletLoader = (ClassContextImpl)loader; - URL base = appletLoader.getBase(); - checkRead(file, base); + /* If no class loader, it's a system class. */ + if (loader != null) + { + /* If not an AppletClassLoader, we don't know what to do */ + if (! (loader instanceof ClassContextImpl)) + throw(new SandboxSecurityException("checkread.unknown", file)); + ClassContext appletLoader = (ClassContextImpl)loader; + URL base = appletLoader.getBase(); + checkRead(file, base); + } + } + } finally { + InCheck.release(); } } public synchronized void checkRead(String file, URL base) { - if( bCheckSecurity && (base != null) && !isSecureLoader() ) { - if (!initACL) - initializeACLs(); - if (readACL == null) - return; - - String realPath = null; - try { - realPath = (new File(file)).getCanonicalPath(); - } catch (IOException e) { - throw(new SandboxSecurityException("checkread.exception1", e.getMessage(), file)); - } - - for (int i = readACL.length ; i-- > 0 ;) { - if (realPath.startsWith(readACL[i])) + try { + InCheck.acquire(); + if( bCheckSecurity && (base != null) && !isSecureLoader() ) { + if (!initACL) + initializeACLs(); + if (readACL == null) + { + InCheck.release(); return; - } - - // if the applet is loaded from a file URL, allow reading - // in that directory - if (base.getProtocol().equals("file")) { - String dir = null; - try { - // If the file url contains spaces (i.e. %20) then URL.getFile() still contains %20 - // File.getCanonicalPath does not replace %20 - // create a string with real spaces instead of %20 - StringBuffer buf= new StringBuffer(256); - String sSpace= "%20"; - String sFile= base.getFile(); - int begin= 0; - int end= 0; - while((end= sFile.indexOf(sSpace, begin)) != -1) { - buf.append( sFile.substring(begin, end)); - buf.append(" "); - begin= end + sSpace.length(); - } - buf.append(sFile.substring(begin)); - - String sWithSpaces= buf.toString(); - dir = (new File(sWithSpaces).getCanonicalPath()); - } catch (IOException e) { // shouldn't happen - throw(new SandboxSecurityException("checkread.exception2", e.toString())); } - if (realPath.startsWith(dir)) - return; - } - throw new SandboxSecurityException("checkread", file, realPath); - } - } - /** + String realPath = null; + try { + realPath = (new File(file)).getCanonicalPath(); + } catch (IOException e) { + throw(new SandboxSecurityException("checkread.exception1", e.getMessage(), file)); + } + + for (int i = readACL.length ; i-- > 0 ;) { + if (realPath.startsWith(readACL[i])) + { + InCheck.release(); + return; + } + } + + // if the applet is loaded from a file URL, allow reading + // in that directory + if (base.getProtocol().equals("file")) { + String dir = null; + try { + // If the file url contains spaces (i.e. %20) then URL.getFile() still contains %20 + // File.getCanonicalPath does not replace %20 + // create a string with real spaces instead of %20 + StringBuffer buf= new StringBuffer(256); + String sSpace= "%20"; + String sFile= base.getFile(); + int begin= 0; + int end= 0; + while((end= sFile.indexOf(sSpace, begin)) != -1) { + buf.append( sFile.substring(begin, end)); + buf.append(" "); + begin= end + sSpace.length(); + } + buf.append(sFile.substring(begin)); + + String sWithSpaces= buf.toString(); + dir = (new File(sWithSpaces).getCanonicalPath()); + } catch (IOException e) { // shouldn't happen + throw(new SandboxSecurityException("checkread.exception2", e.toString())); + } + if (realPath.startsWith(dir)) + { + InCheck.release(); + return; + } + } + throw new SandboxSecurityException("checkread", file, realPath); + } + } finally { + InCheck.release(); + } + + } + /** * Checks to see if the current context or the indicated context are * both allowed to read the given file name. * @param file the system dependent file name @@ -477,35 +568,51 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * be checked * @exception SecurityException If the file is not found. */ - public void checkRead(String file, Object context) { - checkRead(file); - if (context != null) - checkRead(file, (URL) context); + public synchronized void checkRead(String file, Object context) { + try { + InCheck.acquire(); + checkRead(file); + if (context != null) + checkRead(file, (URL) context); + } finally { + InCheck.release(); + } } /** * Check if an applet can write a particular file. */ public synchronized void checkWrite(String file) { - if( bCheckSecurity && inApplet() && !isSecureLoader() ) { - if (!initACL) - initializeACLs(); - if (writeACL == null) - return; - - String realPath = null; - try { - realPath = (new File(file)).getCanonicalPath(); - } catch (IOException e) { - throw(new SandboxSecurityException("checkwrite.exception", e.getMessage(), file)); - } - - for (int i = writeACL.length ; i-- > 0 ;) { - if (realPath.startsWith(writeACL[i])) + try { + InCheck.acquire(); + if( bCheckSecurity && inApplet() && !isSecureLoader() ) { + if (!initACL) + initializeACLs(); + if (writeACL == null) + { + InCheck.release(); return; + } + + String realPath = null; + try { + realPath = (new File(file)).getCanonicalPath(); + } catch (IOException e) { + throw(new SandboxSecurityException("checkwrite.exception", e.getMessage(), file)); + } + + for (int i = writeACL.length ; i-- > 0 ;) { + if (realPath.startsWith(writeACL[i])) + { + InCheck.release(); + return; + } } throw(new SandboxSecurityException("checkwrite", file, realPath)); } + } finally { + InCheck.release(); + } } /** @@ -514,9 +621,14 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * restrictions still apply. */ public synchronized void checkRead(FileDescriptor fd) { - if( bCheckSecurity && !isSecureLoader() ) { - if( (inApplet() && !inClass("java.net.SocketInputStream") ) || (!fd.valid()) ) - throw(new SandboxSecurityException("checkread.fd")); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if( (inApplet() && !inClass("java.net.SocketInputStream") ) || (!fd.valid()) ) + throw(new SandboxSecurityException("checkread.fd")); + } + } finally { + InCheck.release(); } } @@ -526,9 +638,14 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * restrictions still apply. */ public synchronized void checkWrite(FileDescriptor fd) { - if( bCheckSecurity && !isSecureLoader() ) { - if( (inApplet() && !inClass("java.net.SocketOutputStream")) || (!fd.valid()) ) - throw(new SandboxSecurityException("checkwrite.fd")); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if( (inApplet() && !inClass("java.net.SocketOutputStream")) || (!fd.valid()) ) + throw(new SandboxSecurityException("checkwrite.fd")); + } + } finally { + InCheck.release(); } } @@ -541,9 +658,14 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * cannot be subverted by ints that wrap around to an illegal u_short. */ public synchronized void checkListen(int port) { - if( bCheckSecurity && !isSecureLoader() ) { - if (inApplet() && port > 0 && port < PRIVELEGED_PORT) - throw(new SandboxSecurityException("checklisten", String.valueOf(port))); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if (inApplet() && port > 0 && port < PRIVELEGED_PORT) + throw(new SandboxSecurityException("checklisten", String.valueOf(port))); + } + } finally { + InCheck.release(); } } @@ -553,10 +675,15 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * only, depending on the network security setting). */ public synchronized void checkAccept(String host, int port) { - if( bCheckSecurity && !isSecureLoader() ) { - if( inApplet() && port < PRIVELEGED_PORT ) - throw(new SandboxSecurityException("checkaccept", host, String.valueOf(port))); - checkConnect(host, port); + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if( inApplet() && port < PRIVELEGED_PORT ) + throw(new SandboxSecurityException("checkaccept", host, String.valueOf(port))); + checkConnect(host, port); + } + } finally { + InCheck.release(); } } @@ -564,25 +691,39 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * Check if an applet can connect to the given host:port. */ public synchronized void checkConnect(String host, int port) { - if(bCheckSecurity && !isSecureLoader() ) { - ClassLoader loader = currentClassLoader(); - if (loader == null) - return; // Not called from an applet, so it is ok + try { + InCheck.acquire(); + if(bCheckSecurity && !isSecureLoader() ) { + ClassLoader loader = currentClassLoader(); + if (loader == null) + { + InCheck.release(); + return; // Not called from an applet, so it is ok + } - // REMIND: This is only appropriate for our protocol handlers. - int depth = classDepth("sun.net.www.http.HttpClient"); - if (depth > 1) - return; // Called through our http protocol handler + // REMIND: This is only appropriate for our protocol handlers. + int depth = classDepth("sun.net.www.http.HttpClient"); + if (depth > 1) + { + InCheck.release(); + return; // Called through our http protocol handler + } - if(getInCheck()) - return; + if(getInCheck()) + { + InCheck.release(); + return; + } - if (loader instanceof ClassContextImpl) { - ClassContext appletLoader = (ClassContextImpl)loader; - checkConnect(appletLoader.getBase().getHost(), host); - } else { - throw(new SandboxSecurityException("checkconnect.unknown")); + if (loader instanceof ClassContextImpl) { + ClassContext appletLoader = (ClassContextImpl)loader; + checkConnect(appletLoader.getBase().getHost(), host); + } else { + throw(new SandboxSecurityException("checkconnect.unknown")); + } } + } finally { + InCheck.release(); } } @@ -590,139 +731,185 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * Checks to see if the applet and the indicated execution context * are both allowed to connect to the indicated host and port. */ - public void checkConnect(String host, int port, Object context) { - checkConnect(host, port); - if (context != null) - checkConnect(((URL) context).getHost(), host); + public synchronized void checkConnect(String host, int port, Object context) { + try { + InCheck.acquire(); + checkConnect(host, port); + if (context != null) + checkConnect(((URL) context).getHost(), host); + } finally { + InCheck.release(); + } } public synchronized void checkConnect(String fromHost, String toHost, boolean trustP) { - if( bCheckSecurity && !isSecureLoader() ) { - if (fromHost == null) - return; - - switch (networkMode) { - case NETWORK_NONE: - throw(new SandboxSecurityException("checkconnect.networknone", fromHost, toHost)); - - case NETWORK_HOST: - /* - * The policy here is as follows: - * - * - if the strings match, and we know the IP address for it - * we allow the connection. The calling code downstream will - * substitute the IP in their request to the proxy if needed. - * - if the strings don't match, and we can get the IP of - * both hosts then - * - if the IPs match, we allow the connection - * - if they don't we throw(an exception - * - if the string match works and we don't know the IP address - * then we consult the trustProxy property, and if that is true, - * we allow the connection. - * set inCheck so InetAddress knows it doesn't have to - * check security. - */ - try { - inCheck = true; - InetAddress toHostAddr, fromHostAddr; - if (!fromHost.equals(toHost)) { - try { - // the only time we allow non-matching strings - // is when IPs and the IPs match. - toHostAddr = InetAddress.getByName(toHost); - fromHostAddr = InetAddress.getByName(fromHost); - - if( fromHostAddr.equals(toHostAddr) ) - return; - else - throw(new SandboxSecurityException("checkconnect.networkhost1", toHost, fromHost)); - - } catch (UnknownHostException e) { - throw(new SecurityException("checkconnect.networkhost2" + toHost + fromHost)); -// throw(new SandboxSecurityException("checkconnect.networkhost2", toHost, fromHost)); - } - } else { - try { - toHostAddr = InetAddress.getByName(toHost); - - // strings match: if we have IP, we're homefree, - // otherwise we check the properties. - return; - // getBoolean really defaults to false. - } catch (UnknownHostException e) { - if( trustP ) - return; - else - throw(new SandboxSecurityException("checkconnect.networkhost3", toHost)); - } - } - } finally { - inCheck = false; + try { + InCheck.acquire(); + if( bCheckSecurity && !isSecureLoader() ) { + if (fromHost == null) + { + InCheck.release(); + return; } - case NETWORK_UNRESTRICTED: - return; + switch (networkMode) { + case NETWORK_NONE: + throw(new SandboxSecurityException("checkconnect.networknone", fromHost, toHost)); + + case NETWORK_HOST: + /* + * The policy here is as follows: + * + * - if the strings match, and we know the IP address for it + * we allow the connection. The calling code downstream will + * substitute the IP in their request to the proxy if needed. + * - if the strings don't match, and we can get the IP of + * both hosts then + * - if the IPs match, we allow the connection + * - if they don't we throw(an exception + * - if the string match works and we don't know the IP address + * then we consult the trustProxy property, and if that is true, + * we allow the connection. + * set inCheck so InetAddress knows it doesn't have to + * check security. + */ + try { + inCheck = true; + InetAddress toHostAddr, fromHostAddr; + if (!fromHost.equals(toHost)) { + try { + // the only time we allow non-matching strings + // is when IPs and the IPs match. + toHostAddr = InetAddress.getByName(toHost); + fromHostAddr = InetAddress.getByName(fromHost); + + if( fromHostAddr.equals(toHostAddr) ) + { + InCheck.release(); + return; + } + else + { + throw(new SandboxSecurityException( + "checkconnect.networkhost1", toHost, fromHost)); + } + + } catch (UnknownHostException e) { + throw(new SecurityException("checkconnect.networkhost2" + toHost + fromHost)); +// throw(new SandboxSecurityException("checkconnect.networkhost2", toHost, fromHost)); + } + } else { + try { + toHostAddr = InetAddress.getByName(toHost); + InCheck.release(); + // strings match: if we have IP, we're homefree, + // otherwise we check the properties. + return; + // getBoolean really defaults to false. + } catch (UnknownHostException e) { + if( trustP ) + { + InCheck.release(); + return; + } + else + { + throw(new SandboxSecurityException( + "checkconnect.networkhost3", toHost)); + } + } + } + } finally { + inCheck = false; + } + + case NETWORK_UNRESTRICTED: + InCheck.release(); + return; + } + throw(new SandboxSecurityException("checkconnect", fromHost, toHost)); } - throw(new SandboxSecurityException("checkconnect", fromHost, toHost)); + } finally { + InCheck.release(); } } /** - * Check if an applet from a host can connect to another + * check if an applet from a host can connect to another * host. This usually means that you need to determine whether * the hosts are inside or outside the firewall. For now applets * can only access the host they came from. */ public synchronized void checkConnect(String fromHost, String toHost) { - checkConnect(fromHost, toHost, Boolean.getBoolean("trustProxy")); + try { + InCheck.acquire(); + checkConnect(fromHost, toHost, Boolean.getBoolean("trustProxy")); + } finally { + InCheck.release(); + } } /** * Checks to see if top-level windows can be created by the caller. */ public synchronized boolean checkTopLevelWindow(Object window) { - if( bCheckSecurity && inClassLoader() && !isSecureLoader() ) { - /* XXX: this used to return depth > 3. However, this lets */ - /* some applets create frames without warning strings. */ - return false; + boolean ret = true; + try { + InCheck.acquire(); + if( bCheckSecurity && inClassLoader() && !isSecureLoader() ) { + /* XXX: this used to return depth > 3. However, this lets */ + /* some applets create frames without warning strings. */ + ret = false; + } + } finally { + InCheck.release(); } - return true; + return ret; } /** * Check if an applet can access a package. */ public synchronized void checkPackageAccess(String pkg) { - if( bCheckSecurity && inClassLoader() && !isSecureLoader() ) { - if( pkg.equals( "stardiv.applet" ) - // Das AWT von StarDivision - || pkg.equals( "stardiv.look" ) - || pkg.equals( "netscape.javascript" ) ) - return; + try { + InCheck.acquire(); - final String forbidden[] = new String[]{ - "com.sun.star.uno", - "com.sun.star.lib.uno", - "com.sun.star.comp.connections", - "com.sun.star.comp.loader", - "com.sun.star.comp.servicemanager" - }; + if( bCheckSecurity && inClassLoader() && !isSecureLoader() ) { + if( pkg.equals( "stardiv.applet" ) + // Das AWT von StarDivision + || pkg.equals( "stardiv.look" ) + || pkg.equals( "netscape.javascript" ) ) + { + InCheck.release(); + return; + } + + final String forbidden[] = new String[]{ + "com.sun.star.uno", + "com.sun.star.lib.uno", + "com.sun.star.comp.connections", + "com.sun.star.comp.loader", + "com.sun.star.comp.servicemanager" + }; - for(int j = 0; j < forbidden.length; ++ j) { - if(pkg.startsWith(forbidden[j])) - throw(new SandboxSecurityException("checkpackageaccess2", pkg)); - } - - int i = pkg.indexOf('.'); - while (i > 0) { - String subpkg = pkg.substring(0,i); - if( Boolean.getBoolean("package.restrict.access." + subpkg) ) - throw(new SandboxSecurityException("checkpackageaccess", pkg)); - i = pkg.indexOf('.',i+1); + for(int j = 0; j < forbidden.length; ++ j) { + if(pkg.startsWith(forbidden[j])) + throw(new SandboxSecurityException("checkpackageaccess2", pkg)); + } + + int i = pkg.indexOf('.'); + while (i > 0) { + String subpkg = pkg.substring(0,i); + if( Boolean.getBoolean("package.restrict.access." + subpkg) ) + throw(new SandboxSecurityException("checkpackageaccess", pkg)); + i = pkg.indexOf('.',i+1); + } } + } finally { + InCheck.release(); } } @@ -730,6 +917,11 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * Check if an applet can define classes in a package. */ public synchronized void checkPackageDefinition(String pkg) { + try { + InCheck.acquire(); + } finally { + InCheck.release(); + } return; /* if (!inClassLoader()) @@ -751,8 +943,13 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * Check if an applet can set a networking-related object factory. */ public synchronized void checkSetFactory() { - if( bCheckSecurity && inApplet() && !isSecureLoader() ) - throw(new SandboxSecurityException("cannotsetfactory")); + try { + InCheck.acquire(); + if( bCheckSecurity && inApplet() && !isSecureLoader() ) + throw(new SandboxSecurityException("cannotsetfactory")); + } finally { + InCheck.release(); + } } /** @@ -769,65 +966,108 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage * * XXX: Should VerifyClassAccess here? Should Class.forName do it? */ - public void checkMemberAccess(Class clazz, int which) { - if( bCheckSecurity && !isSecureLoader() ) { - if( which != java.lang.reflect.Member.PUBLIC ) { - ClassLoader currentLoader = currentClassLoader(); - if( currentLoader != null && (classLoaderDepth() <= 3) ) - /* Client is an untrusted class loaded by currentLoader */ - if( currentLoader != clazz.getClassLoader() ) - throw(new SandboxSecurityException("checkmemberaccess")); + public synchronized void checkMemberAccess(Class clazz, int which) { + try { + InCheck.acquire(); + + if( bCheckSecurity && !isSecureLoader() ) { + if( which != java.lang.reflect.Member.PUBLIC ) { + ClassLoader currentLoader = currentClassLoader(); + if( currentLoader != null && (classLoaderDepth() <= 3) ) + /* Client is an untrusted class loaded by currentLoader */ + if( currentLoader != clazz.getClassLoader() ) + throw(new SandboxSecurityException("checkmemberaccess")); + } } + } finally { + InCheck.release(); } } /** * Checks to see if an applet can initiate a print job request. */ - public void checkPrintJobAccess() { - if( bCheckSecurity && inApplet() && !isSecureLoader() ) - throw(new SandboxSecurityException("checkgetprintjob")); + public synchronized void checkPrintJobAccess() { + try { + InCheck.acquire(); + if( bCheckSecurity && inApplet() && !isSecureLoader() ) + throw(new SandboxSecurityException("checkgetprintjob")); + } finally { + InCheck.release(); + } } /** * Checks to see if an applet can get System Clipboard access. */ - public void checkSystemClipboardAccess() { - if( bCheckSecurity && inApplet() && !isSecureLoader() ) - throw(new SandboxSecurityException("checksystemclipboardaccess")); + public synchronized void checkSystemClipboardAccess() { + try { + InCheck.acquire(); + + if( bCheckSecurity && inApplet() && !isSecureLoader() ) + throw(new SandboxSecurityException("checksystemclipboardaccess")); + } finally { + InCheck.release(); + } } /** * Checks to see if an applet can get EventQueue access. */ - public void checkAwtEventQueueAccess() { - if( bCheckSecurity && inClassLoader() && !isSecureLoader() ) { + public synchronized void checkAwtEventQueueAccess() { + try { + InCheck.acquire(); + if( bCheckSecurity && inClassLoader() && !isSecureLoader() ) { // throw(new SandboxSecurityException("checkawteventqueueaccess")); + } + } finally { + InCheck.release(); } } /** * Checks to see if an applet can perform a given operation. */ - public void checkSecurityAccess(String action) { - if( bCheckSecurity && inApplet() && !isSecureLoader() ) - throw(new SandboxSecurityException("checksecurityaccess", action)); + public synchronized void checkSecurityAccess(String action) { + try { + InCheck.acquire(); + if( bCheckSecurity && inApplet() && !isSecureLoader() ) + throw(new SandboxSecurityException("checksecurityaccess", action)); + } finally { + InCheck.release(); + } } /** * Returns the thread group of the applet. We consult the classloader * if there is one. */ - public ThreadGroup getThreadGroup() { - /* First we check if any classloaded thing is on the stack. */ - ClassLoader loader = currentClassLoader(); - if (loader != null && (loader instanceof ClassContextImpl)) { - if( inThreadGroup( Thread.currentThread() ) ) - return Thread.currentThread().getThreadGroup(); - ClassContextImpl appletLoader = (ClassContextImpl)loader; - return appletLoader.getThreadGroup(); - } else - return super.getThreadGroup(); + public synchronized ThreadGroup getThreadGroup() { + ThreadGroup group = null; + try { + InCheck.acquire(); + /* First we check if any classloaded thing is on the stack. */ + ClassLoader loader = currentClassLoader(); + if (loader != null && (loader instanceof ClassContextImpl)) + { + if( inThreadGroup( Thread.currentThread() ) ) + { + group = Thread.currentThread().getThreadGroup(); + } + else + { + ClassContextImpl appletLoader = (ClassContextImpl)loader; + group = appletLoader.getThreadGroup(); + } + } + else + { + group = super.getThreadGroup(); + } + } finally { + InCheck.release(); + } + return group; } public void debug(String s) { @@ -835,17 +1075,117 @@ public class SandboxSecurity extends SecurityManager //implements SecurityManage System.err.println(s); } - private boolean isSecureLoader() { - ClassLoader loader = currentClassLoader(); - if (loader != null) { - if (loader instanceof ClassContextImpl) { - return !((ClassContextImpl) loader).checkSecurity(); + // This method is called from within the checkXXX method which + //already track if this class is on the stack by using InCheck. + private synchronized boolean isSecureLoader() { + InIsSecureLoader.acquire(); + try { + boolean bReturn = false; + ClassLoader loader = currentClassLoader(); + if (loader != null) { + if (loader instanceof ClassContextImpl) { + bReturn = !((ClassContextImpl) loader).checkSecurity(); + } else { + bReturn = true; // fremder ClassLoader: kann machen was er will + } } else { - return true; // fremder ClassLoader: kann machen was er will + bReturn = true; } - } else { - return true; + return bReturn; + } finally { + InIsSecureLoader.release(); } } + + + + /* In checkPermission we trap calls which are not covered by the old + (1.1) SecurityManager functions. This is necessary, because whenever + applets are used then the SecurityManager is set and Java components + may cause a checkPermission call. Then, if a user has not specified + permissions for this component, a SecurityException will be thrown + and the component fails to work. + + Calls to java.lang.SecurityManager.inClassLoader result in + a call to this function. For example, a checkPackageAccess with the + package java.text resulted in a call to this function with the permission + All_Permission. We use the member InCheck in order to determine if we + are in one of the check functions. If we are then checkPermissions does + nothing. The calling checkXXX does the required check anyway. + + We cannot override + void checkPermission(Permission perm, Object context) + because we do not know if in the thread, which is represented by context, + one of our security functions has been called. That is, we have no + access to InCheck or the class loaders to dertime if we grant permission. + + */ + public synchronized void checkPermission(java.security.Permission perm) + { + //isSecureClassLoader calls SecurityManager.currentClassLoader, which then + //calls this function to check if we have AllPermission. If so, then currentClassLoader + //returns null. Therefore we must throw and exception here. This is similar with + //the functions inClassLoader and classLoaderDepth. + if (InIsSecureLoader.inRecursion() + || InInClassLoader.inRecursion() + || InClassLoaderDepth.inRecursion()) + { + if (perm.implies(allPerm)) + throw(new SandboxSecurityException("checkPermission ", perm.toString())); + } + if (InCheck.inRecursion() == false + && isSecureLoader() == false) + { + throw(new SandboxSecurityException("checkPermission ", perm.toString())); + } + } + + protected boolean inClassLoader() + { + InInClassLoader.acquire(); + try + { + return super.inClassLoader(); + } finally { + InInClassLoader.release(); + } + } + + protected int classLoaderDepth() + { + InClassLoaderDepth.acquire(); + try + { + return super.classLoaderDepth(); + } finally { + InClassLoaderDepth.release(); + } + + } } +class RecursionCounter +{ + void acquire() + { + int count = ((Integer)refCount.get()).intValue(); + refCount.set(new Integer(++count)); + } + + void release() + { + int count = ((Integer)refCount.get()).intValue(); + refCount.set(new Integer(--count)); + } + + boolean inRecursion() { + int count = ((Integer)refCount.get()).intValue(); + return count > 0; + } + + private ThreadLocal refCount = new ThreadLocal() { + protected synchronized Object initialValue() { + return new Integer(0); + } + }; +}