diff options
author | Michael Koch <konqueror@gmx.de> | 2004-06-03 09:16:41 +0000 |
---|---|---|
committer | Michael Koch <konqueror@gmx.de> | 2004-06-03 09:16:41 +0000 |
commit | 4e450e3b7e2a0e95162a2c0c02d564796a89bea2 (patch) | |
tree | 68d1fd7959d83cb1768230f71017ce23f56ee604 /vm | |
parent | d01086467f65eb260dc22cc622c9c668b6e564fd (diff) | |
download | classpath-4e450e3b7e2a0e95162a2c0c02d564796a89bea2.tar.gz |
2004-06-03 Casey Marshall <csm@gnu.org>
* java/security/AccessController.java
(doPrivileged(PrivilegedAction,AccessControlContext)): call
VMAccessController.pushContext and popContext.
(doPrivileged(PrivilegedExceptionAction,AccessControlContext)):
likewise.
(getContext): call VMAccessController.getContext.
* java/security/Makefile.am
(EXTRA_DIST): add IntersectingDomainCombiner.java.
* gnu/java/security/Makefile.am
(EXTRA_DIST): add PolicyFile.java
* vm/reference/java/Makefile.am
(SUBDIRS): add security.
* java/security/IntersectingDomainCombiner.java: new file.
* gnu/java/security/PolicyFile.java: new file.
* vm/reference/java/security/VMAccessController.java: new file.
* vm/reference/java/security/Makefile.am: new file
2004-06-03 Michael Koch <konqerorq@gmx.de>
* configure.ac: Added vm/runtime/java/security/Makefile to output
files.
Diffstat (limited to 'vm')
-rw-r--r-- | vm/reference/java/Makefile.am | 2 | ||||
-rw-r--r-- | vm/reference/java/security/Makefile.am | 5 | ||||
-rw-r--r-- | vm/reference/java/security/VMAccessController.java | 236 |
3 files changed, 242 insertions, 1 deletions
diff --git a/vm/reference/java/Makefile.am b/vm/reference/java/Makefile.am index 8c16975d6..e842cd1de 100644 --- a/vm/reference/java/Makefile.am +++ b/vm/reference/java/Makefile.am @@ -1,3 +1,3 @@ # used by automake to generate Makefile.in -SUBDIRS = lang io +SUBDIRS = lang io security diff --git a/vm/reference/java/security/Makefile.am b/vm/reference/java/security/Makefile.am new file mode 100644 index 000000000..468d7cfe0 --- /dev/null +++ b/vm/reference/java/security/Makefile.am @@ -0,0 +1,5 @@ +# used by automake to generate Makefile.in + + +EXTRA_DIST = \ +VMAccessController.java diff --git a/vm/reference/java/security/VMAccessController.java b/vm/reference/java/security/VMAccessController.java new file mode 100644 index 000000000..a9a580f92 --- /dev/null +++ b/vm/reference/java/security/VMAccessController.java @@ -0,0 +1,236 @@ +/* VMAccessController.java -- VM-specific access controller methods. + Copyright (C) 2004 Free Software Foundation, Inc. + +This program 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. + +This program 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 this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 java.security; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +final class VMAccessController +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * A mapping between pairs (<i>thread</i>, <i>classname</i>) to access + * control contexts. The <i>thread</i> and <i>classname</i> are the thread + * and <i>classname</i> current as of the last call to doPrivileged with + * an AccessControlContext argument. + */ + private static final Map contexts = Collections.synchronizedMap(new HashMap()); + + private static final ThreadLocal inGetContext = new ThreadLocal(); + + private final static AccessControlContext DEFAULT_CONTEXT; + static + { + CodeSource source = new CodeSource(null, null); + Permissions permissions = new Permissions(); + permissions.add(new AllPermission()); + ProtectionDomain[] domain = new ProtectionDomain[] { + new ProtectionDomain(source, permissions) + }; + DEFAULT_CONTEXT = new AccessControlContext(domain); + } + + private static final boolean DEBUG = false; + private static void debug (String msg) + { + System.err.print (">>> VMAccessController: "); + System.err.println (msg); + } + + // Constructors. + // ------------------------------------------------------------------------- + + private VMAccessController() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Relate a class (which should be an instance of {@link PrivilegedAction} + * with an access control context. This method is used by {@link + * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)} + * to set up the context that will be returned by {@link #getContext()}. + * This method relates the class to the current thread, so contexts + * pushed from one thread will not be available to another. + * + * @param acc The access control context. + * @param clazz The class that implements {@link PrivilegedAction}. + */ + static void pushContext (AccessControlContext acc, Class clazz) + { + ArrayList pair = new ArrayList (2); + pair.add (Thread.currentThread()); + pair.add (clazz); + if (DEBUG) debug ("pushing " + pair); + contexts.put (pair, acc); + } + + /** + * Removes the relation of a class to an {@link AccessControlContext}. + * This method is used by {@link AccessController} when exiting from a + * call to {@link + * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}. + * + * @param clazz The class that implements {@link PrivilegedAction}. + */ + static void popContext (Class clazz) + { + ArrayList pair = new ArrayList (2); + pair.add (Thread.currentThread()); + pair.add (clazz); + if (DEBUG) debug ("popping " + pair); + contexts.remove (pair); + } + + /** + * Examine the method stack of the currently running thread, and create + * an {@link AccessControlContext} filled in with the appropriate {@link + * ProtectionDomain} objects given this stack. + * + * @return The context. + */ + static AccessControlContext getContext() + { + // If we are already in getContext, but called a method that needs + // a permission check, return the all-permissive context so methods + // called from here succeed. + // + // XXX is this necessary? We should verify if there are any calls in + // the stack below this method that require permission checks. + Boolean inCall = (Boolean) inGetContext.get(); + if (inCall != null && inCall.booleanValue()) + { + if (DEBUG) debug ("already in getContext"); + return DEFAULT_CONTEXT; + } + + Object[][] stack = getStack(); + Class[] classes = (Class[]) stack[0]; + String[] methods = (String[]) stack[1]; + + inGetContext.set (Boolean.TRUE); + + if (DEBUG) debug (">>> got trace of length " + classes.length); + + HashSet domains = new HashSet(); + HashSet seenDomains = new HashSet(); + AccessControlContext context = null; + + // We walk down the stack, adding each ProtectionDomain for each + // class in the call stack. If we reach a call to doPrivileged, + // we don't add any more stack frames. We skip the first three stack + // frames, since they comprise the calls to getStack, getContext, + // and AccessController.getContext. + for (int i = 3; i < classes.length; i++) + { + Class clazz = classes[i]; + String method = methods[i]; + + if (DEBUG) debug (">>> checking " + clazz + "." + method); + + if (DEBUG) debug (">>> loader = " + clazz.getClassLoader()); + + if (clazz.equals (AccessController.class) + && method.equals ("doPrivileged")) + { + // If there was a call to doPrivileged with a supplied context, + // return that context. + List pair = new ArrayList(2); + pair.add (Thread.currentThread()); + pair.add (classes[i-1]); + if (contexts.containsKey (pair)) + context = (AccessControlContext) contexts.get (pair); + break; + } + + ProtectionDomain domain = clazz.getProtectionDomain(); + + if (domain == null) + continue; + if (seenDomains.contains (domain)) + continue; + seenDomains.add (domain); + + // Create a static snapshot of this domain, which may change over time + // if the current policy changes. + domains.add (new ProtectionDomain (domain.getCodeSource(), + domain.getPermissions())); + } + + if (DEBUG) debug ("created domains: " + domains); + + ProtectionDomain[] result = (ProtectionDomain[]) + domains.toArray (new ProtectionDomain[domains.size()]); + + // Intersect the derived protection domain with the context supplied + // to doPrivileged. + if (context != null) + context = new AccessControlContext (result, context, + IntersectingDomainCombiner.SINGLETON); + // No context was supplied. Return the derived one. + else + context = new AccessControlContext (result); + + inGetContext.set (Boolean.FALSE); + return context; + } + + /** + * Returns a snapshot of the current call stack as a pair of arrays: + * the first an array of classes in the call stack, the second an array + * of strings containing the method names in the call stack. The two + * arrays match up, meaning that method <i>i</i> is declared in class + * <i>i</i>. The arrays are clean; it will only contain Java methods, + * and no element of the list should be null. + * + * <p>XXX note: this interface (VMAccessController) would possibly be + * cleaner if we had a method similar to this, but returned an array + * of java.lang.reflect.Method objects. Then, instead of having this + * much logic in this class, we put everything in AccessController, + * and simply have this single getStack method for a VM to implement. + */ + private static native Object[][] getStack(); +} |