Save This Page
Home » openjdk-7 » java » security » [javadoc | source]
    1   /* VMAccessController.java -- VM-specific access controller methods.
    2      Copyright (C) 2004, 2005  Free Software Foundation, Inc.
    3   
    4   This program is free software; you can redistribute it and/or modify
    5   it under the terms of the GNU General Public License as published by
    6   the Free Software Foundation; either version 2, or (at your option)
    7   any later version.
    8   
    9   This program is distributed in the hope that it will be useful, but
   10   WITHOUT ANY WARRANTY; without even the implied warranty of
   11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12   General Public License for more details.
   13   
   14   You should have received a copy of the GNU General Public License
   15   along with this program; see the file COPYING.  If not, write to the
   16   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   17   02110-1301 USA.
   18   
   19   Linking this library statically or dynamically with other modules is
   20   making a combined work based on this library.  Thus, the terms and
   21   conditions of the GNU General Public License cover the whole
   22   combination.
   23   
   24   As a special exception, the copyright holders of this library give you
   25   permission to link this library with independent modules to produce an
   26   executable, regardless of the license terms of these independent
   27   modules, and to copy and distribute the resulting executable under
   28   terms of your choice, provided that you also meet, for each linked
   29   independent module, the terms and conditions of the license of that
   30   module.  An independent module is a module which is not derived from
   31   or based on this library.  If you modify this library, you may extend
   32   this exception to your version of the library, but you are not
   33   obligated to do so.  If you do not wish to do so, delete this
   34   exception statement from your version. */
   35   
   36   
   37   package java.security;
   38   
   39   import java.util.HashSet;
   40   import java.util.LinkedList;
   41   
   42   final class VMAccessController
   43   {
   44   
   45     // Fields.
   46     // -------------------------------------------------------------------------
   47   
   48     /**
   49      * This is a per-thread stack of AccessControlContext objects (which can
   50      * be null) for each call to AccessController.doPrivileged in each thread's
   51      * call stack. We use this to remember which context object corresponds to
   52      * which call.
   53      */
   54     private static final ThreadLocal contexts = new ThreadLocal();
   55   
   56     /**
   57      * This is a Boolean that, if set, tells getContext that it has already
   58      * been called once, allowing us to handle recursive permission checks
   59      * caused by methods getContext calls.
   60      */
   61     private static final ThreadLocal inGetContext = new ThreadLocal();
   62   
   63     /**
   64      * And we return this all-permissive context to ensure that privileged
   65      * methods called from getContext succeed.
   66      */
   67     private static final AccessControlContext DEFAULT_CONTEXT;
   68     static
   69     {
   70       CodeSource source = new CodeSource(null, null);
   71       Permissions permissions = new Permissions();
   72       permissions.add(new AllPermission());
   73       ProtectionDomain[] domain = new ProtectionDomain[] {
   74         new ProtectionDomain(source, permissions)
   75       };
   76       DEFAULT_CONTEXT = new AccessControlContext(domain);
   77     }
   78   
   79     private static final boolean DEBUG = gnu.classpath.Configuration.DEBUG;
   80     private static void debug(String msg)
   81     {
   82       System.err.print(">>> VMAccessController: ");
   83       System.err.println(msg);
   84     }
   85   
   86     // Constructors.
   87     // -------------------------------------------------------------------------
   88   
   89     private VMAccessController() { }
   90   
   91     // Class methods.
   92     // -------------------------------------------------------------------------
   93   
   94     /**
   95      * Relate a class (which should be an instance of {@link PrivilegedAction}
   96      * with an access control context. This method is used by {@link
   97      * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}
   98      * to set up the context that will be returned by {@link #getContext()}.
   99      * This method relates the class to the current thread, so contexts
  100      * pushed from one thread will not be available to another.
  101      *
  102      * @param acc The access control context.
  103      */
  104     static void pushContext (AccessControlContext acc)
  105     {
  106       if (DEBUG)
  107         debug("pushing " + acc);
  108       LinkedList stack = (LinkedList) contexts.get();
  109       if (stack == null)
  110         {
  111            if (DEBUG)
  112              debug("no stack... creating ");
  113           stack = new LinkedList();
  114           contexts.set(stack);
  115         }
  116       stack.addFirst(acc);
  117     }
  118   
  119     /**
  120      * Removes the relation of a class to an {@link AccessControlContext}.
  121      * This method is used by {@link AccessController} when exiting from a
  122      * call to {@link
  123      * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}.
  124      */
  125     static void popContext()
  126     {
  127       if (DEBUG)
  128         debug("popping context");
  129   
  130       // Stack should never be null, nor should it be empty, if this method
  131       // and its counterpart has been called properly.
  132       LinkedList stack = (LinkedList) contexts.get();
  133       if (stack != null)
  134         {
  135           stack.removeFirst();
  136           if (stack.isEmpty())
  137             contexts.set(null);
  138         }
  139       else if (DEBUG)
  140         {
  141           debug("no stack during pop?????");
  142         }
  143     }
  144   
  145     /**
  146      * Examine the method stack of the currently running thread, and create
  147      * an {@link AccessControlContext} filled in with the appropriate {@link
  148      * ProtectionDomain} objects given this stack.
  149      *
  150      * @return The context.
  151      */
  152     static AccessControlContext getContext()
  153     {
  154       // If we are already in getContext, but called a method that needs
  155       // a permission check, return the all-permissive context so methods
  156       // called from here succeed.
  157       //
  158       // XXX is this necessary? We should verify if there are any calls in
  159       // the stack below this method that require permission checks.
  160       Boolean inCall = (Boolean) inGetContext.get();
  161       if (inCall != null && inCall.booleanValue())
  162         {
  163           if (DEBUG)
  164             debug("already in getContext");
  165           return DEFAULT_CONTEXT;
  166         }
  167   
  168       inGetContext.set(Boolean.TRUE);
  169   
  170       Object[][] stack = getStack();
  171       Class[] classes = (Class[]) stack[0];
  172       String[] methods = (String[]) stack[1];
  173   
  174       if (DEBUG)
  175         debug("got trace of length " + classes.length);
  176   
  177       HashSet domains = new HashSet();
  178       HashSet seenDomains = new HashSet();
  179       AccessControlContext context = null;
  180       int privileged = 0;
  181   
  182       // We walk down the stack, adding each ProtectionDomain for each
  183       // class in the call stack. If we reach a call to doPrivileged,
  184       // we don't add any more stack frames. We skip the first three stack
  185       // frames, since they comprise the calls to getStack, getContext,
  186       // and AccessController.getContext.
  187       for (int i = 3; i < classes.length && privileged < 2; i++)
  188         {
  189           Class clazz = classes[i];
  190           String method = methods[i];
  191   
  192           if (DEBUG)
  193             {
  194               debug("checking " + clazz + "." + method);
  195               // subject to getClassLoader RuntimePermission
  196               debug("loader = " + clazz.getClassLoader());
  197             }
  198   
  199           // If the previous frame was a call to doPrivileged, then this is
  200           // the last frame we look at.
  201           if (privileged == 1)
  202             privileged = 2;
  203   
  204           if (clazz.equals (AccessController.class)
  205               && method.equals ("doPrivileged"))
  206             {
  207               // If there was a call to doPrivileged with a supplied context,
  208               // return that context. If using JAAS doAs*, it should be 
  209   	    // a context with a SubjectDomainCombiner
  210               LinkedList l = (LinkedList) contexts.get();
  211               if (l != null)
  212                 context = (AccessControlContext) l.getFirst();
  213               privileged = 1;
  214             }
  215   
  216           // subject to getProtectionDomain RuntimePermission
  217   	ProtectionDomain domain = clazz.getProtectionDomain();
  218   
  219           if (domain == null)
  220             continue;
  221           if (seenDomains.contains(domain))
  222             continue;
  223           seenDomains.add(domain);
  224   
  225           // Create a static snapshot of this domain, which may change over time
  226           // if the current policy changes.
  227           domains.add(new ProtectionDomain(domain.getCodeSource(),
  228                                            domain.getPermissions()));
  229         }
  230   
  231       if (DEBUG)
  232         debug("created domains: " + domains);
  233   
  234       ProtectionDomain[] result = (ProtectionDomain[])
  235         domains.toArray(new ProtectionDomain[domains.size()]);
  236   
  237       if (context != null)
  238         {
  239           DomainCombiner dc = context.getDomainCombiner ();
  240           // If the supplied context had no explicit DomainCombiner, use
  241           // our private version, which computes the intersection of the
  242           // context's domains with the derived set.
  243           if (dc == null)
  244             context = new AccessControlContext
  245               (IntersectingDomainCombiner.SINGLETON.combine
  246                (result, context.getProtectionDomains ()));
  247           // Use the supplied DomainCombiner. This should be secure,
  248           // because only trusted code may create an
  249           // AccessControlContext with a custom DomainCombiner.
  250           else
  251             context = new AccessControlContext (result, context, dc);
  252         }
  253       // No context was supplied. Return the derived one.
  254       else
  255         context = new AccessControlContext (result);
  256   
  257       inGetContext.set(Boolean.FALSE);
  258       return context;
  259     }
  260   
  261     /**
  262      * Returns a snapshot of the current call stack as a pair of arrays:
  263      * the first an array of classes in the call stack, the second an array
  264      * of strings containing the method names in the call stack. The two
  265      * arrays match up, meaning that method <i>i</i> is declared in class
  266      * <i>i</i>. The arrays are clean; it will only contain Java methods,
  267      * and no element of the list should be null.
  268      *
  269      * <p>The default implementation returns an empty stack, which will be
  270      * interpreted as having no permissions whatsoever.
  271      *
  272      * @return A pair of arrays describing the current call stack. The first
  273      *    element is an array of Class objects, and the second is an array
  274      *    of Strings comprising the method names.
  275      */
  276     private static Object[][] getStack()
  277     {
  278       return new Object[][] { new Class[0], new String[0] };
  279     }
  280   }

Save This Page
Home » openjdk-7 » java » security » [javadoc | source]