home *** CD-ROM | disk | FTP | other *** search
Java Source | 1997-01-27 | 15.4 KB | 545 lines |
- /*
- * @(#)AppletSecurity.java 1.38 96/04/29
- *
- * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for NON-COMMERCIAL purposes and without
- * fee is hereby granted provided that this copyright notice
- * appears in all copies. Please refer to the file "copyright.html"
- * for further important copyright and licensing information.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
- * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
- * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
- */
-
- package sun.applet;
-
- import java.io.File;
- import java.io.FileDescriptor;
- import java.net.URL;
- import java.net.InetAddress;
- import java.net.UnknownHostException;
- import java.util.StringTokenizer;
- import java.util.Vector;
-
- /**
- * This class defines an applet security policy
- *
- * @version 1.38, 04/29/96
- * @author Sami Shaio
- * @author Arthur van Hoff
- */
- public
- class AppletSecurity extends SecurityManager {
- private static boolean debug = false;
-
- boolean initACL;
- String readACL[];
- String writeACL[];
- int networkMode;
-
- final static int NETWORK_NONE = 1;
- final static int NETWORK_HOST = 2;
- final static int NETWORK_UNRESTRICTED = 3;
-
- /**
- * Construct and initialize.
- */
- public AppletSecurity() {
- reset();
- }
-
- /**
- * Reset from Properties
- */
- public void reset() {
- String str = System.getProperty("appletviewer.security.mode");
- if (str == null) {
- str = "host";
- }
-
- if (str.equals("unrestricted")) {
- networkMode = NETWORK_UNRESTRICTED;
- } else if (str.equals("none")) {
- networkMode = NETWORK_NONE;
- } else {
- networkMode = NETWORK_HOST;
- }
- }
-
- /**
- * True if called directly from an applet.
- */
- boolean fromApplet() {
- return classLoaderDepth() == 1;
- }
-
- /**
- * True if called indirectly from an applet.
- */
- boolean inApplet() {
- return inClassLoader();
- }
-
- /**
- * The only variable that currently affects whether an applet can
- * perform certain operations is the host it came from.
- */
- public Object getSecurityContext() {
- AppletClassLoader loader = (AppletClassLoader)currentClassLoader();
- if (loader == null) {
- return null;
- } else {
- return loader.base;
- }
- }
-
- /**
- * Applets are not allowed to create class loaders, or even execute any
- * of ClassLoader's methods. The name of this method should be changed to
- * checkClassLoaderOperation or somesuch.
- */
- public synchronized void checkCreateClassLoader() {
- if (classLoaderDepth() == 2) {
- throw new AppletSecurityException("classloader");
- }
- }
-
- /**
- * Applets are not allowed to manipulate threads outside
- * applet thread groups.
- */
- public synchronized void checkAccess(Thread t) {
- if (classLoaderDepth()==2 && !(t.getThreadGroup() instanceof AppletThreadGroup)) {
- throw new AppletSecurityException("thread");
- }
- }
-
- /**
- * Applets are not allowed to manipulate thread groups outside
- * applet thread groups.
- */
- public synchronized void checkAccess(ThreadGroup g) {
- if (classLoaderDepth()==4 && !(g instanceof AppletThreadGroup)) {
- throw new AppletSecurityException("threadgroup", g.toString());
- }
- }
-
- /**
- * Applets are not allowed to exit the VM.
- */
- public synchronized void checkExit(int status) {
- if (inApplet()) {
- throw new AppletSecurityException("exit", String.valueOf(status));
- }
- }
-
- /**
- * Applets are not allowed to fork processes.
- */
- public synchronized void checkExec(String cmd){
- if (inApplet()) {
- throw new AppletSecurityException("exec", cmd);
- }
- }
-
- /**
- * Applets are not allowed to link dynamic libraries.
- */
- public synchronized void checkLink(String lib){
- switch (classLoaderDepth()) {
- case 2: // Runtime.load
- case 3: // System.loadLibrary
- throw new AppletSecurityException("link", lib);
- default:
- break;
- }
- }
-
- /**
- * Applets are not allowed to access the entire system properties
- * list, only properties explicitly labeled as accessible to applets.
- */
- public synchronized void checkPropertiesAccess() {
- if (classLoaderDepth() == 2) {
- throw new AppletSecurityException("properties");
- }
- }
-
- /**
- * Applets can access the system property named by <i>key</i>
- * only if its twin <i>key.applet</i> property is set to true.
- * For example, the property <code>java.home</code> can be read by
- * applets only if <code>java.home.applet</code> is <code>true</code>.
- */
- public synchronized void checkPropertyAccess(String key) {
- if (classLoaderDepth() == 2) {
- if (!"true".equalsIgnoreCase(System.getProperty(key + ".applet"))) {
- throw new AppletSecurityException("properties");
- }
- }
- }
-
- /**
- * Parse an ACL. Deals with "~" and "+"
- */
- void parseACL(Vector v, String path, String defaultPath) {
- StringTokenizer t = new StringTokenizer(path, System.getProperty("path.separator"));
- while (t.hasMoreTokens()) {
- String dir = t.nextToken();
- if (dir.startsWith("~")) {
- v.addElement(System.getProperty("user.home") + dir.substring(1));
- } else if (dir.equals("+")) {
- if (defaultPath != null) {
- parseACL(v, defaultPath, null);
- }
- } else {
- v.addElement(dir);
- }
- }
- }
-
- /**
- * Parse an ACL.
- */
- String[] parseACL(String path, String defaultPath) {
- if (path == null) {
- return new String[0];
- }
- if (path.equals("*")) {
- return null;
- }
- Vector v = new Vector();
- parseACL(v, path, defaultPath);
-
- String acl[] = new String[v.size()];
- v.copyInto(acl);
- return acl;
- }
-
- /**
- * Initialize ACLs. Called only once.
- */
- void initializeACLs() {
- readACL = parseACL(System.getProperty("acl.read"),
- System.getProperty("acl.read.default"));
- writeACL = parseACL(System.getProperty("acl.write"),
- System.getProperty("acl.write.default"));
- initACL = true;
- }
-
- /**
- * Check if an applet can read a particular file.
- */
- public synchronized void checkRead(String file) {
- AppletClassLoader loader = (AppletClassLoader)currentClassLoader();
- if (loader != null) {
- checkRead(file, loader.base);
- }
- }
-
- public synchronized void checkRead(String file, URL base) {
- if (base != null) {
- if (!initACL) {
- initializeACLs();
- }
- if (readACL == null) {
- return;
- }
- for (int i = readACL.length ; i-- > 0 ;) {
- if (file.startsWith(readACL[i])) {
- return;
- }
- }
- // if the applet is loaded from a file URL, allow reading
- // in that directory
- if (base.getProtocol().equals("file")) {
- String dir = base.getFile().replace('/', File.separatorChar);
- if (file.replace('/', File.separatorChar).startsWith(dir)) {
- return;
- }
- }
-
- throw new AppletSecurityException("file.read", file);
- }
- }
-
- /**
- * 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
- * @param context the alternate execution context which must also
- * 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);
- }
- }
-
- /**
- * Check if an applet can write a particular file.
- */
- public synchronized void checkWrite(String file) {
- if (inApplet()) {
- if (!initACL) {
- initializeACLs();
- }
- if (writeACL == null) {
- return;
- }
- for (int i = writeACL.length ; i-- > 0 ;) {
- if (file.startsWith(writeACL[i])) {
- return;
- }
- }
- throw new AppletSecurityException("file.write", file);
- }
- }
-
- /**
- * Check if an applet can delete a particular file.
- */
- public void checkDelete(String file) {
- if (inApplet()) {
- throw new AppletSecurityException("file.delete",file);
- }
- }
-
- /**
- * Applets are not allowed to open file descriptors unless
- * it is done through a socket, in which case other access
- * restrictions still apply.
- */
- public synchronized void checkRead(FileDescriptor fd) {
- if ((inApplet() && !inClass("java.net.SocketInputStream"))
- || (!fd.valid()) ) {
- throw new AppletSecurityException("fd.read");
- }
- }
-
- /**
- * Applets are not allowed to open file descriptors unless
- * it is done through a socket, in which case other access
- * restrictions still apply.
- */
- public synchronized void checkWrite(FileDescriptor fd) {
- if ( (inApplet() && !inClass("java.net.SocketOutputStream"))
- || (!fd.valid()) ) {
- throw new AppletSecurityException("fd.write");
- }
- }
-
- /**
- * For now applets can't listen on any port.
- */
- public synchronized void checkListen(int port) {
- if (inApplet()) {
- throw new AppletSecurityException("socket.listen", String.valueOf(port));
- }
- }
-
- /**
- * For now applets can't accept connections on any port.
- */
- public synchronized void checkAccept(String host, int port) {
- if (inApplet()) {
- throw new AppletSecurityException("socket.accept", host + ":" + String.valueOf(port));
- }
- }
-
- /**
- * Check if an applet can connect to the given host:port.
- */
- public synchronized void checkConnect(String host, int port) {
- AppletClassLoader loader = (AppletClassLoader)currentClassLoader();
- if (loader == null) {
- // Not called from an applet, so it is ok
- return;
- }
-
- // This is only appropriate for our protocol handlers.
- int depth = classDepth("sun.net.www.http.HttpClient");
- if (depth > 1) {
- // Called through our http protocol handler
- return;
- }
- checkConnect(loader.base.getHost(), host);
- }
-
- /**
- * 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 fromHost, String toHost, boolean trustP) {
- if (fromHost == null) {
- return;
- }
-
- switch (networkMode) {
- case NETWORK_NONE:
- throw new AppletSecurityException("socket.connect", 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 get have
- // IPs and the IPs match.
- toHostAddr = InetAddress.getByName(toHost);
- fromHostAddr = InetAddress.getByName(fromHost);
- if (fromHostAddr.equals(toHostAddr)) {
- return;
- } else {
- throw new AppletSecurityException("Couldn't connect to " +
- toHost +
- " with origin from " +
- fromHost);
- }
- } catch (UnknownHostException e) {
- throw new AppletSecurityException("Couldn't resolve IP for host " + toHost
- + " or for " + 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 AppletSecurityException("Could not resolve IP for host " +
- toHost +
- ". See the trustProxy property.");
- }
- }
- }
-
- } finally {
- inCheck = false;
- }
-
-
- case NETWORK_UNRESTRICTED:
- return;
- }
- throw new AppletSecurityException("connect", fromHost + "->" + toHost);
- }
-
- /**
- * 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"));
- }
-
- /**
- * Checks to see if top-level windows can be created by the caller.
- */
- public synchronized boolean checkTopLevelWindow(Object window) {
- if (inClassLoader()) {
- /* XXX: this used to return depth > 3. However, this lets */
- /* some applets create frames without warning strings. */
- return false;
- }
- return true;
- }
-
- /**
- * Check if an applet can access a package.
- */
- public synchronized void checkPackageAccess(String pkg) {
- int i = pkg.indexOf('.');
- while (i > 0)
- {
- String subpkg = pkg.substring(0,i);
- if (inClassLoader() && Boolean.getBoolean("package.restrict.access." + subpkg)) {
- throw new SecurityException();
- }
- i = pkg.indexOf('.',i+1);
- }
- if (inClassLoader() && Boolean.getBoolean("package.restrict.access." + pkg)) {
- throw new SecurityException();
- }
- }
-
- /**
- * Check if an applet can define classes in a package.
- */
- public synchronized void checkPackageDefinition(String pkg) {
- int i = pkg.indexOf('.');
- while (i > 0)
- {
- String subpkg = pkg.substring(0,i);
- if (Boolean.getBoolean("package.restrict.definition." + subpkg)) {
- throw new SecurityException();
- }
- i = pkg.indexOf('.',i+1);
- }
- if (Boolean.getBoolean("package.restrict.definition." + pkg)) {
- throw new SecurityException();
- }
- }
-
- /**
- * Check if an applet can set a networking-related object factory.
- */
- public synchronized void checkSetFactory() {
- throw new SecurityException();
- }
-
- public void debug(String s) {
- if (debug) {
- System.err.println(s);
- }
- }
-
- /**
- * Applets are not allowed to put up file dialogs.
- */
- public synchronized void checkFileDialog(){
- if (inApplet()) {
- throw new AppletSecurityException("filedialog");
- }
- }
-
- }
-