// Copyright (C) 2001-2003 Jon A. Maxwell (JAM) // // 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. package net.sourceforge.jnlp.runtime; import static net.sourceforge.jnlp.runtime.Translator.R; import java.awt.Frame; import java.awt.Window; import java.lang.ref.WeakReference; import java.net.SocketPermission; import java.security.AllPermission; import java.security.AccessControlException; import java.security.Permission; import java.security.SecurityPermission; import javax.swing.JWindow; import net.sourceforge.jnlp.JNLPFile; import net.sourceforge.jnlp.security.SecurityDialogs.AccessType; import net.sourceforge.jnlp.services.ServiceUtil; import net.sourceforge.jnlp.util.WeakList; import sun.awt.AWTSecurityManager; import sun.awt.AppContext; import sun.security.util.SecurityConstants; /** * Security manager for JNLP environment. This security manager * cannot be replaced as it always denies attempts to replace the * security manager or policy.
* * The JNLP security manager tracks windows created by an * application, allowing those windows to be disposed when the * application exits but the JVM does not. If security is not * enabled then the first application to call System.exit will * halt the JVM.
*
* @author Jon A. Maxwell (JAM) - initial author
* @version $Revision: 1.17 $
*/
class JNLPSecurityManager extends AWTSecurityManager {
// todo: some apps like JDiskReport can close the VM even when
// an exit class is set - fix!
// todo: create an event dispatch thread for each application,
// so that the context classloader doesn't have to be switched
// to the foreground application (the currently the approach
// since some apps need their classloader as event dispatch
// thread's context classloader).
// todo: use a custom Permission object to identify the current
// application in an AccessControlContext by setting a side
// effect in its implies method. Use a custom
// AllPermissions-like permission to do this for apps granted
// all permissions (but investigate whether this will nuke
// the all-permission optimizations in the JRE).
// todo: does not exit app if close button pressed on JFrame
// with CLOSE_ON_EXIT (or whatever) set; if doesn't exit, use an
// WindowListener to catch WindowClosing event, then if exit is
// called immediately afterwards from AWT thread.
// todo: deny all permissions to applications that should have
// already been 'shut down' by closing their resources and
// interrupt the threads if operating in a shared-VM (exit class
// set). Deny will probably will slow checks down a lot though.
// todo: weak remember last getProperty application and
// re-install properties if another application calls, or find
// another way for different apps to have different properties
// in java.lang.Sytem with the same names.
/** only class that can exit the JVM, if set */
private Object exitClass = null;
/** this exception prevents exiting the JVM */
private SecurityException closeAppEx = // making here prevents huge stack traces
new SecurityException(R("RShutdown"));
/** weak list of windows created */
private WeakList
*
* Calls not from Runtime.exit or with no exit class set will
* behave normally, and the exit class can always exit the JVM.
*/
public void checkExit(int status) {
// applets are not allowed to exit, but the plugin main class (primordial loader) is
Class stack[] = getClassContext();
if (!exitAllowed) {
for (int i = 0; i < stack.length; i++)
if (stack[i].getClassLoader() != null)
throw new AccessControlException("Applets may not call System.exit()");
}
super.checkExit(status);
boolean realCall = (stack[1] == Runtime.class);
if (isExitClass(stack)) // either exitClass called or no exitClass set
return; // to Runtime.exit or fake call to see if app has permission
// not called from Runtime.exit()
if (!realCall) {
// apps that can't exit should think they can exit normally
super.checkExit(status);
return;
}
// but when they really call, stop only the app instead of the JVM
ApplicationInstance app = getApplication(Thread.currentThread(), stack, 0);
if (app == null) {
throw new SecurityException(R("RExitNoApp"));
}
app.destroy();
throw closeAppEx;
}
protected void disableExit() {
exitAllowed = false;
}
/**
* This returns the appropriate {@link AppContext}. Hooks in AppContext
* check if the current {@link SecurityManager} is an instance of
* AWTSecurityManager and if so, call this method to give it a chance to
* return the appropriate appContext based on the application that is
* running.
*
* This can be called from any thread (possibly a swing thread) to find out
* the AppContext for the thread (which may correspond to a particular
* applet).
*/
@Override
public AppContext getAppContext() {
ApplicationInstance app = getApplication();
if (app == null) {
/*
* if we cannot find an application based on the code on the stack,
* then assume it is the main application
*/
return mainAppContext;
} else {
return app.getAppContext();
}
}
/**
* Tests if a client can get access to the AWT event queue. This version allows
* complete access to the EventQueue for its own AppContext-specific EventQueue.
*
* FIXME there are probably huge security implications for this. Eg:
* http://hg.openjdk.java.net/jdk7/awt/jdk/rev/8022709a306d
*
* @exception SecurityException if the caller does not have
* permission to accesss the AWT event queue.
*/
public void checkAwtEventQueueAccess() {
/*
* this is the templace of the code that should allow applets access to
* eventqueues
*/
// AppContext appContext = AppContext.getAppContext();
// ApplicationInstance instance = getApplication();
// if ((appContext == mainAppContext) && (instance != null)) {
// If we're about to allow access to the main EventQueue,
// and anything untrusted is on the class context stack,
// disallow access.
super.checkAwtEventQueueAccess();
// }
}
}