1 /* VMAccessController.java -- VM-specific access controller methods.
2 Copyright (C) 2004, 2005, 2006 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)
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
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
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
46 // -------------------------------------------------------------------------
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
54 private static final ThreadLocal contexts
= new ThreadLocal();
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();
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
;
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
);
87 // -------------------------------------------------------------------------
89 private VMAccessController() { }
92 // -------------------------------------------------------------------------
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 (Thread
.currentThread() == null)
110 debug("pushing " + acc
);
111 LinkedList stack
= (LinkedList
) contexts
.get();
115 debug("no stack... creating ");
116 stack
= new LinkedList();
123 * Removes the relation of a class to an {@link AccessControlContext}.
124 * This method is used by {@link AccessController} when exiting from a
126 * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}.
128 static void popContext()
130 if (Thread
.currentThread() == null)
134 debug("popping context");
136 // Stack should never be null, nor should it be empty, if this method
137 // and its counterpart has been called properly.
138 LinkedList stack
= (LinkedList
) contexts
.get();
147 debug("no stack during pop?????");
152 * Examine the method stack of the currently running thread, and create
153 * an {@link AccessControlContext} filled in with the appropriate {@link
154 * ProtectionDomain} objects given this stack.
156 * @return The context.
158 static AccessControlContext
getContext()
160 // If the VM is initializing return the all-permissive context
161 // so that any security checks succeed.
162 if (Thread
.currentThread() == null)
163 return DEFAULT_CONTEXT
;
165 // If we are already in getContext, but called a method that needs
166 // a permission check, return the all-permissive context so methods
167 // called from here succeed.
169 // XXX is this necessary? We should verify if there are any calls in
170 // the stack below this method that require permission checks.
171 Boolean inCall
= (Boolean
) inGetContext
.get();
172 if (inCall
!= null && inCall
.booleanValue())
175 debug("already in getContext");
176 return DEFAULT_CONTEXT
;
179 inGetContext
.set(Boolean
.TRUE
);
181 Object
[][] stack
= getStack();
182 Class
[] classes
= (Class
[]) stack
[0];
183 String
[] methods
= (String
[]) stack
[1];
186 debug("got trace of length " + classes
.length
);
188 HashSet domains
= new HashSet();
189 HashSet seenDomains
= new HashSet();
190 AccessControlContext context
= null;
193 // We walk down the stack, adding each ProtectionDomain for each
194 // class in the call stack. If we reach a call to doPrivileged,
195 // we don't add any more stack frames. We skip the first three stack
196 // frames, since they comprise the calls to getStack, getContext,
197 // and AccessController.getContext.
198 for (int i
= 3; i
< classes
.length
&& privileged
< 2; i
++)
200 Class clazz
= classes
[i
];
201 String method
= methods
[i
];
205 debug("checking " + clazz
+ "." + method
);
206 // subject to getClassLoader RuntimePermission
207 debug("loader = " + clazz
.getClassLoader());
210 // If the previous frame was a call to doPrivileged, then this is
211 // the last frame we look at.
215 if (clazz
.equals (AccessController
.class)
216 && method
.equals ("doPrivileged"))
218 // If there was a call to doPrivileged with a supplied context,
219 // return that context. If using JAAS doAs*, it should be
220 // a context with a SubjectDomainCombiner
221 LinkedList l
= (LinkedList
) contexts
.get();
223 context
= (AccessControlContext
) l
.getFirst();
227 // subject to getProtectionDomain RuntimePermission
228 ProtectionDomain domain
= clazz
.getProtectionDomain();
232 if (seenDomains
.contains(domain
))
234 seenDomains
.add(domain
);
236 // Create a static snapshot of this domain, which may change over time
237 // if the current policy changes.
238 domains
.add(new ProtectionDomain(domain
.getCodeSource(),
239 domain
.getPermissions()));
243 debug("created domains: " + domains
);
245 ProtectionDomain
[] result
= (ProtectionDomain
[])
246 domains
.toArray(new ProtectionDomain
[domains
.size()]);
250 DomainCombiner dc
= context
.getDomainCombiner ();
251 // If the supplied context had no explicit DomainCombiner, use
252 // our private version, which computes the intersection of the
253 // context's domains with the derived set.
255 context
= new AccessControlContext
256 (IntersectingDomainCombiner
.SINGLETON
.combine
257 (result
, context
.getProtectionDomains ()));
258 // Use the supplied DomainCombiner. This should be secure,
259 // because only trusted code may create an
260 // AccessControlContext with a custom DomainCombiner.
262 context
= new AccessControlContext (result
, context
, dc
);
264 // No context was supplied. Return the derived one.
266 context
= new AccessControlContext (result
);
268 inGetContext
.set(Boolean
.FALSE
);
273 * Returns a snapshot of the current call stack as a pair of arrays:
274 * the first an array of classes in the call stack, the second an array
275 * of strings containing the method names in the call stack. The two
276 * arrays match up, meaning that method <i>i</i> is declared in class
277 * <i>i</i>. The arrays are clean; it will only contain Java methods,
278 * and no element of the list should be null.
280 * @return A pair of arrays describing the current call stack. The first
281 * element is an array of Class objects, and the second is an array
282 * of Strings comprising the method names.
284 private static native Object
[][] getStack();