Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / vm / reference / java / security / VMAccessController.java
blobda13c6889463ba590e45c61a44372aa51c74c8b0
1 /* VMAccessController.java -- VM-specific access controller methods.
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
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.
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.
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.
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.
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. */
37 package java.security;
39 import java.util.HashSet;
40 import java.util.LinkedList;
42 final class VMAccessController
45 // Fields.
46 // -------------------------------------------------------------------------
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.
54 private static final ThreadLocal contexts = new ThreadLocal();
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.
61 private static final ThreadLocal inGetContext = new ThreadLocal();
63 /**
64 * And we return this all-permissive context to ensure that privileged
65 * methods called from getContext succeed.
67 private static final AccessControlContext DEFAULT_CONTEXT;
68 static
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)
76 DEFAULT_CONTEXT = new AccessControlContext(domain);
79 private static final boolean DEBUG = gnu.classpath.Configuration.DEBUG;
80 private static void debug(String msg)
82 System.err.print(">>> VMAccessController: ");
83 System.err.println(msg);
86 // Constructors.
87 // -------------------------------------------------------------------------
89 private VMAccessController() { }
91 // Class methods.
92 // -------------------------------------------------------------------------
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.
102 * @param acc The access control context.
104 static void pushContext (AccessControlContext acc)
106 if (DEBUG)
107 debug("pushing " + acc);
108 LinkedList stack = (LinkedList) contexts.get();
109 if (stack == null)
111 if (DEBUG)
112 debug("no stack... creating ");
113 stack = new LinkedList();
114 contexts.set(stack);
116 stack.addFirst(acc);
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)}.
125 static void popContext()
127 if (DEBUG)
128 debug("popping context");
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)
135 stack.removeFirst();
136 if (stack.isEmpty())
137 contexts.set(null);
139 else if (DEBUG)
141 debug("no stack during pop?????");
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.
150 * @return The context.
152 static AccessControlContext getContext()
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.
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())
163 if (DEBUG)
164 debug("already in getContext");
165 return DEFAULT_CONTEXT;
168 inGetContext.set(Boolean.TRUE);
170 Object[][] stack = getStack();
171 Class[] classes = (Class[]) stack[0];
172 String[] methods = (String[]) stack[1];
174 if (DEBUG)
175 debug("got trace of length " + classes.length);
177 HashSet domains = new HashSet();
178 HashSet seenDomains = new HashSet();
179 AccessControlContext context = null;
180 int privileged = 0;
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++)
189 Class clazz = classes[i];
190 String method = methods[i];
192 if (DEBUG)
194 debug("checking " + clazz + "." + method);
195 // subject to getClassLoader RuntimePermission
196 debug("loader = " + clazz.getClassLoader());
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;
204 if (clazz.equals (AccessController.class)
205 && method.equals ("doPrivileged"))
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;
216 // subject to getProtectionDomain RuntimePermission
217 ProtectionDomain domain = clazz.getProtectionDomain();
219 if (domain == null)
220 continue;
221 if (seenDomains.contains(domain))
222 continue;
223 seenDomains.add(domain);
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()));
231 if (DEBUG)
232 debug("created domains: " + domains);
234 ProtectionDomain[] result = (ProtectionDomain[])
235 domains.toArray(new ProtectionDomain[domains.size()]);
237 if (context != null)
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);
253 // No context was supplied. Return the derived one.
254 else
255 context = new AccessControlContext (result);
257 inGetContext.set(Boolean.FALSE);
258 return context;
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.
269 * <p>The default implementation returns an empty stack, which will be
270 * interpreted as having no permissions whatsoever.
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.
276 private static Object[][] getStack()
278 return new Object[][] { new Class[0], new String[0] };