OSDN Git Service

PR libgcj/46774: Create dynamic ProtectionDomain instances which check the system...
[pf3gnuchains/gcc-fork.git] / libjava / java / security / VMAccessController.java
1 /* VMAccessController.java -- VM-specific access controller methods.
2    Copyright (C) 2004, 2005, 2006  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    * And we return this all-permissive context to ensure that privileged
50    * methods called from getContext succeed.
51    */
52   private static final AccessControlContext DEFAULT_CONTEXT;
53   static
54   {
55     CodeSource source = new CodeSource(null, null);
56     Permissions permissions = new Permissions();
57     permissions.add(new AllPermission());
58     ProtectionDomain[] domain = new ProtectionDomain[] {
59       new ProtectionDomain(source, permissions, null, null)
60     };
61     DEFAULT_CONTEXT = new AccessControlContext(domain);
62   }
63
64   private static final boolean DEBUG = gnu.classpath.Configuration.DEBUG;
65   private static void debug(String msg)
66   {
67     System.err.print(">>> VMAccessController: ");
68     System.err.println(msg);
69   }
70
71   // Constructors.
72   // -------------------------------------------------------------------------
73
74   private VMAccessController() { }
75
76   // Class methods.
77   // -------------------------------------------------------------------------
78
79   /**
80    * Relate a class (which should be an instance of {@link PrivilegedAction}
81    * with an access control context. This method is used by {@link
82    * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}
83    * to set up the context that will be returned by {@link #getContext()}.
84    * This method relates the class to the current thread, so contexts
85    * pushed from one thread will not be available to another.
86    *
87    * @param acc The access control context.
88    */
89   static void pushContext (AccessControlContext acc)
90   {
91     // Can't really do anything while the VM is initializing.
92     VMAccessControlState state = VMAccessControlState.getThreadState();
93     if (state == null)
94       return;
95
96     if (DEBUG)
97       debug("pushing " + acc);
98
99     LinkedList stack = state.getContexts();
100     stack.addFirst(acc);
101   }
102
103   /**
104    * Removes the relation of a class to an {@link AccessControlContext}.
105    * This method is used by {@link AccessController} when exiting from a
106    * call to {@link
107    * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}.
108    */
109   static void popContext()
110   {
111     // Can't really do anything while the VM is initializing.
112     VMAccessControlState state = VMAccessControlState.getThreadState();
113     if (state == null)
114       return;
115
116     if (DEBUG)
117       debug("popping context");
118
119     // Stack should never be null, nor should it be empty, if this method
120     // and its counterpart has been called properly.
121     LinkedList stack = state.getContexts();
122     if (!stack.isEmpty())
123       {
124         stack.removeFirst();
125       }
126     else if (DEBUG)
127       {
128         debug("no stack during pop?????");
129       }
130   }
131
132   /**
133    * Examine the method stack of the currently running thread, and create
134    * an {@link AccessControlContext} filled in with the appropriate {@link
135    * ProtectionDomain} objects given this stack.
136    *
137    * @return The context.
138    */
139   static AccessControlContext getContext()
140   {
141     // If the VM is initializing return the all-permissive context
142     // so that any security checks succeed.
143     VMAccessControlState state = VMAccessControlState.getThreadState();
144     if (state == null)
145       return DEFAULT_CONTEXT;
146
147     // If we are already in getContext, but called a method that needs
148     // a permission check, return the all-permissive context so methods
149     // called from here succeed.
150     //
151     // XXX is this necessary? We should verify if there are any calls in
152     // the stack below this method that require permission checks.
153     if (state.isInGetContext())
154       {
155         if (DEBUG)
156           debug("already in getContext");
157         return DEFAULT_CONTEXT;
158       }
159
160     state.setInGetContext(true);
161
162     Object[] stack = getStack();
163     Class[] classes = (Class[]) stack[0];
164     boolean privileged = ((Boolean) stack[1]).booleanValue();
165
166     if (DEBUG)
167       debug("got trace of length " + classes.length);
168
169     HashSet domains = new HashSet();
170     HashSet seenDomains = new HashSet();
171     AccessControlContext context = null;
172
173     // We walk down the stack, adding each ProtectionDomain for each
174     // class in the call stack. If we reach a call to doPrivileged,
175     // we don't add any more stack frames. We skip the first three stack
176     // frames, since they comprise the calls to getStack, getContext,
177     // and AccessController.getContext.
178     for (int i = 3; i < classes.length; i++)
179       {
180         Class clazz = classes[i];
181         ClassLoader loader = clazz.getClassLoader();
182
183         if (DEBUG)
184           {
185             debug("checking " + clazz);
186             // subject to getClassLoader RuntimePermission
187             debug("loader = " + loader);
188           }
189
190         if (privileged && i == classes.length - 2)
191           {
192             // If there was a call to doPrivileged with a supplied context,
193             // return that context. If using JAAS doAs*, it should be
194             // a context with a SubjectDomainCombiner
195             LinkedList l = state.getContexts();
196             if (!l.isEmpty())
197               context = (AccessControlContext) l.getFirst();
198           }
199
200         // subject to getProtectionDomain RuntimePermission
201         ProtectionDomain domain = clazz.getProtectionDomain();
202
203         if (domain == null)
204           continue;
205         if (seenDomains.contains(domain))
206           continue;
207         seenDomains.add(domain);
208
209         // Create a static snapshot of this domain, which may change over time
210         // if the current policy changes.
211         domains.add(new ProtectionDomain(domain.getCodeSource(),
212                                          domain.getPermissions(),
213                                          loader, null));
214       }
215
216     if (DEBUG)
217       debug("created domains: " + domains);
218
219     ProtectionDomain[] result = (ProtectionDomain[])
220       domains.toArray(new ProtectionDomain[domains.size()]);
221
222     if (context != null)
223       {
224         DomainCombiner dc = context.getDomainCombiner ();
225         // If the supplied context had no explicit DomainCombiner, use
226         // our private version, which computes the intersection of the
227         // context's domains with the derived set.
228         if (dc == null)
229           context = new AccessControlContext
230             (IntersectingDomainCombiner.SINGLETON.combine
231              (result, context.getProtectionDomains ()));
232         // Use the supplied DomainCombiner. This should be secure,
233         // because only trusted code may create an
234         // AccessControlContext with a custom DomainCombiner.
235         else
236           context = new AccessControlContext (result, context, dc);
237       }
238     // No context was supplied. Return the derived one.
239     else
240       context = new AccessControlContext (result);
241
242     state.setInGetContext(false);
243     return context;
244   }
245
246   /**
247    * Returns a snapshot of the current call stack as a two-element
248    * array. The first element is an array of classes in the call
249    * stack, and the second element is a boolean value indicating
250    * whether the trace stopped early because a call to doPrivileged
251    * was encountered.  If this boolean value is true then the call to
252    * doPrivileged will be the second-last frame in the returned trace.
253    *
254    * @return A snapshot of the current call stack.
255    */
256   private static native Object[] getStack();
257 }