mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			283 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			283 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Java
		
	
	
	
/* VMAccessController.java -- VM-specific access controller methods.
 | 
						|
   Copyright (C) 2004, 2005  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., 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 java.security;
 | 
						|
 | 
						|
import java.util.HashSet;
 | 
						|
import java.util.LinkedList;
 | 
						|
 | 
						|
final class VMAccessController
 | 
						|
{
 | 
						|
 | 
						|
  // Fields.
 | 
						|
  // -------------------------------------------------------------------------
 | 
						|
 | 
						|
  /**
 | 
						|
   * This is a per-thread stack of AccessControlContext objects (which can
 | 
						|
   * be null) for each call to AccessController.doPrivileged in each thread's
 | 
						|
   * call stack. We use this to remember which context object corresponds to
 | 
						|
   * which call.
 | 
						|
   */
 | 
						|
  private static final ThreadLocal contexts = new ThreadLocal();
 | 
						|
 | 
						|
  /**
 | 
						|
   * This is a Boolean that, if set, tells getContext that it has already
 | 
						|
   * been called once, allowing us to handle recursive permission checks
 | 
						|
   * caused by methods getContext calls.
 | 
						|
   */
 | 
						|
  private static final ThreadLocal inGetContext = new ThreadLocal();
 | 
						|
 | 
						|
  /**
 | 
						|
   * And we return this all-permissive context to ensure that privileged
 | 
						|
   * methods called from getContext succeed.
 | 
						|
   */
 | 
						|
  private static final 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, null, null)
 | 
						|
    };
 | 
						|
    DEFAULT_CONTEXT = new AccessControlContext(domain);
 | 
						|
  }
 | 
						|
 | 
						|
  private static final boolean DEBUG = gnu.classpath.Configuration.DEBUG;
 | 
						|
  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.
 | 
						|
   */
 | 
						|
  static void pushContext (AccessControlContext acc)
 | 
						|
  {
 | 
						|
    if (DEBUG)
 | 
						|
      debug("pushing " + acc);
 | 
						|
    LinkedList stack = (LinkedList) contexts.get();
 | 
						|
    if (stack == null)
 | 
						|
      {
 | 
						|
         if (DEBUG)
 | 
						|
           debug("no stack... creating ");
 | 
						|
        stack = new LinkedList();
 | 
						|
        contexts.set(stack);
 | 
						|
      }
 | 
						|
    stack.addFirst(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)}.
 | 
						|
   */
 | 
						|
  static void popContext()
 | 
						|
  {
 | 
						|
    if (DEBUG)
 | 
						|
      debug("popping context");
 | 
						|
 | 
						|
    // Stack should never be null, nor should it be empty, if this method
 | 
						|
    // and its counterpart has been called properly.
 | 
						|
    LinkedList stack = (LinkedList) contexts.get();
 | 
						|
    if (stack != null)
 | 
						|
      {
 | 
						|
        stack.removeFirst();
 | 
						|
        if (stack.isEmpty())
 | 
						|
          contexts.set(null);
 | 
						|
      }
 | 
						|
    else if (DEBUG)
 | 
						|
      {
 | 
						|
        debug("no stack during pop?????");
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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;
 | 
						|
      }
 | 
						|
 | 
						|
    inGetContext.set(Boolean.TRUE);
 | 
						|
 | 
						|
    Object[][] stack = getStack();
 | 
						|
    Class[] classes = (Class[]) stack[0];
 | 
						|
    String[] methods = (String[]) stack[1];
 | 
						|
 | 
						|
    if (DEBUG)
 | 
						|
      debug("got trace of length " + classes.length);
 | 
						|
 | 
						|
    HashSet domains = new HashSet();
 | 
						|
    HashSet seenDomains = new HashSet();
 | 
						|
    AccessControlContext context = null;
 | 
						|
    int privileged = 0;
 | 
						|
 | 
						|
    // 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 && privileged < 2; i++)
 | 
						|
      {
 | 
						|
        Class clazz = classes[i];
 | 
						|
        String method = methods[i];
 | 
						|
        ClassLoader loader = clazz.getClassLoader();
 | 
						|
 | 
						|
        if (DEBUG)
 | 
						|
          {
 | 
						|
            debug("checking " + clazz + "." + method);
 | 
						|
            // subject to getClassLoader RuntimePermission
 | 
						|
            debug("loader = " + loader);
 | 
						|
          }
 | 
						|
 | 
						|
        // If the previous frame was a call to doPrivileged, then this is
 | 
						|
        // the last frame we look at.
 | 
						|
        if (privileged == 1)
 | 
						|
          privileged = 2;
 | 
						|
 | 
						|
        if (clazz.equals (AccessController.class)
 | 
						|
            && method.equals ("doPrivileged"))
 | 
						|
          {
 | 
						|
            // If there was a call to doPrivileged with a supplied context,
 | 
						|
            // return that context. If using JAAS doAs*, it should be
 | 
						|
            // a context with a SubjectDomainCombiner
 | 
						|
            LinkedList l = (LinkedList) contexts.get();
 | 
						|
            if (l != null)
 | 
						|
              context = (AccessControlContext) l.getFirst();
 | 
						|
            privileged = 1;
 | 
						|
          }
 | 
						|
 | 
						|
        // subject to getProtectionDomain RuntimePermission
 | 
						|
        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(),
 | 
						|
                                         loader, null));
 | 
						|
      }
 | 
						|
 | 
						|
    if (DEBUG)
 | 
						|
      debug("created domains: " + domains);
 | 
						|
 | 
						|
    ProtectionDomain[] result = (ProtectionDomain[])
 | 
						|
      domains.toArray(new ProtectionDomain[domains.size()]);
 | 
						|
 | 
						|
    if (context != null)
 | 
						|
      {
 | 
						|
        DomainCombiner dc = context.getDomainCombiner ();
 | 
						|
        // If the supplied context had no explicit DomainCombiner, use
 | 
						|
        // our private version, which computes the intersection of the
 | 
						|
        // context's domains with the derived set.
 | 
						|
        if (dc == null)
 | 
						|
          context = new AccessControlContext
 | 
						|
            (IntersectingDomainCombiner.SINGLETON.combine
 | 
						|
             (result, context.getProtectionDomains ()));
 | 
						|
        // Use the supplied DomainCombiner. This should be secure,
 | 
						|
        // because only trusted code may create an
 | 
						|
        // AccessControlContext with a custom DomainCombiner.
 | 
						|
        else
 | 
						|
          context = new AccessControlContext (result, context, dc);
 | 
						|
      }
 | 
						|
    // 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>The default implementation returns an empty stack, which will be
 | 
						|
   * interpreted as having no permissions whatsoever.
 | 
						|
   *
 | 
						|
   * @return A pair of arrays describing the current call stack. The first
 | 
						|
   *    element is an array of Class objects, and the second is an array
 | 
						|
   *    of Strings comprising the method names.
 | 
						|
   */
 | 
						|
  private static Object[][] getStack()
 | 
						|
  {
 | 
						|
    return new Object[][] { new Class[0], new String[0] };
 | 
						|
  }
 | 
						|
}
 |