1 /*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.security;
27
28 import java.util.HashMap;
29 import java.util.ArrayList;
30 import java.net.URL;
31
32 import sun.security.util.Debug;
33
34 /**
35 * This class extends ClassLoader with additional support for defining
36 * classes with an associated code source and permissions which are
37 * retrieved by the system policy by default.
38 *
39 * @author Li Gong
40 * @author Roland Schemers
41 */
42 public class SecureClassLoader extends ClassLoader {
43 /*
44 * If initialization succeed this is set to true and security checks will
45 * succeed. Otherwise the object is not initialized and the object is
46 * useless.
47 */
48 private boolean initialized = false;
49
50 // HashMap that maps CodeSource to ProtectionDomain
51 private HashMap<CodeSource, ProtectionDomain> pdcache =
52 new HashMap<CodeSource, ProtectionDomain>(11);
53
54 private static final Debug debug = Debug.getInstance("scl");
55
56 /**
57 * Creates a new SecureClassLoader using the specified parent
58 * class loader for delegation.
59 *
60 * <p>If there is a security manager, this method first
61 * calls the security manager's <code>checkCreateClassLoader</code>
62 * method to ensure creation of a class loader is allowed.
63 * <p>
64 * @param parent the parent ClassLoader
65 * @exception SecurityException if a security manager exists and its
66 * <code>checkCreateClassLoader</code> method doesn't allow
67 * creation of a class loader.
68 * @see SecurityManager#checkCreateClassLoader
69 */
70 protected SecureClassLoader(ClassLoader parent) {
71 super(parent);
72 // this is to make the stack depth consistent with 1.1
73 SecurityManager security = System.getSecurityManager();
74 if (security != null) {
75 security.checkCreateClassLoader();
76 }
77 initialized = true;
78 }
79
80 /**
81 * Creates a new SecureClassLoader using the default parent class
82 * loader for delegation.
83 *
84 * <p>If there is a security manager, this method first
85 * calls the security manager's <code>checkCreateClassLoader</code>
86 * method to ensure creation of a class loader is allowed.
87 *
88 * @exception SecurityException if a security manager exists and its
89 * <code>checkCreateClassLoader</code> method doesn't allow
90 * creation of a class loader.
91 * @see SecurityManager#checkCreateClassLoader
92 */
93 protected SecureClassLoader() {
94 super();
95 // this is to make the stack depth consistent with 1.1
96 SecurityManager security = System.getSecurityManager();
97 if (security != null) {
98 security.checkCreateClassLoader();
99 }
100 initialized = true;
101 }
102
103 /**
104 * Converts an array of bytes into an instance of class Class,
105 * with an optional CodeSource. Before the
106 * class can be used it must be resolved.
107 * <p>
108 * If a non-null CodeSource is supplied a ProtectionDomain is
109 * constructed and associated with the class being defined.
110 * <p>
111 * @param name the expected name of the class, or <code>null</code>
112 * if not known, using '.' and not '/' as the separator
113 * and without a trailing ".class" suffix.
114 * @param b the bytes that make up the class data. The bytes in
115 * positions <code>off</code> through <code>off+len-1</code>
116 * should have the format of a valid class file as defined
117 * by the
118 * <a href="http://java.sun.com/docs/books/vmspec/">Java
119 * Virtual Machine Specification</a>.
120 * @param off the start offset in <code>b</code> of the class data
121 * @param len the length of the class data
122 * @param cs the associated CodeSource, or <code>null</code> if none
123 * @return the <code>Class</code> object created from the data,
124 * and optional CodeSource.
125 * @exception ClassFormatError if the data did not contain a valid class
126 * @exception IndexOutOfBoundsException if either <code>off</code> or
127 * <code>len</code> is negative, or if
128 * <code>off+len</code> is greater than <code>b.length</code>.
129 *
130 * @exception SecurityException if an attempt is made to add this class
131 * to a package that contains classes that were signed by
132 * a different set of certificates than this class, or if
133 * the class name begins with "java.".
134 */
135 protected final Class<?> defineClass(String name,
136 byte[] b, int off, int len,
137 CodeSource cs)
138 {
139 if (cs == null)
140 return defineClass(name, b, off, len);
141 else
142 return defineClass(name, b, off, len, getProtectionDomain(cs));
143 }
144
145 /**
146 * Converts a {@link java.nio.ByteBuffer <tt>ByteBuffer</tt>}
147 * into an instance of class <tt>Class</tt>, with an optional CodeSource.
148 * Before the class can be used it must be resolved.
149 * <p>
150 * If a non-null CodeSource is supplied a ProtectionDomain is
151 * constructed and associated with the class being defined.
152 * <p>
153 * @param name the expected name of the class, or <code>null</code>
154 * if not known, using '.' and not '/' as the separator
155 * and without a trailing ".class" suffix.
156 * @param b the bytes that make up the class data. The bytes from positions
157 * <tt>b.position()</tt> through <tt>b.position() + b.limit() -1</tt>
158 * should have the format of a valid class file as defined by the
159 * <a href="http://java.sun.com/docs/books/vmspec/">Java Virtual
160 * Machine Specification</a>.
161 * @param cs the associated CodeSource, or <code>null</code> if none
162 * @return the <code>Class</code> object created from the data,
163 * and optional CodeSource.
164 * @exception ClassFormatError if the data did not contain a valid class
165 * @exception SecurityException if an attempt is made to add this class
166 * to a package that contains classes that were signed by
167 * a different set of certificates than this class, or if
168 * the class name begins with "java.".
169 *
170 * @since 1.5
171 */
172 protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,
173 CodeSource cs)
174 {
175 if (cs == null)
176 return defineClass(name, b, (ProtectionDomain)null);
177 else
178 return defineClass(name, b, getProtectionDomain(cs));
179 }
180
181 /**
182 * Returns the permissions for the given CodeSource object.
183 * <p>
184 * This method is invoked by the defineClass method which takes
185 * a CodeSource as an argument when it is constructing the
186 * ProtectionDomain for the class being defined.
187 * <p>
188 * @param codesource the codesource.
189 *
190 * @return the permissions granted to the codesource.
191 *
192 */
193 protected PermissionCollection getPermissions(CodeSource codesource)
194 {
195 check();
196 return new Permissions(); // ProtectionDomain defers the binding
197 }
198
199 /*
200 * Returned cached ProtectionDomain for the specified CodeSource.
201 */
202 private ProtectionDomain getProtectionDomain(CodeSource cs) {
203 if (cs == null)
204 return null;
205
206 ProtectionDomain pd = null;
207 synchronized (pdcache) {
208 pd = pdcache.get(cs);
209 if (pd == null) {
210 PermissionCollection perms = getPermissions(cs);
211 pd = new ProtectionDomain(cs, perms, this, null);
212 if (pd != null) {
213 pdcache.put(cs, pd);
214 if (debug != null) {
215 debug.println(" getPermissions "+ pd);
216 debug.println("");
217 }
218 }
219 }
220 }
221 return pd;
222 }
223
224 /*
225 * Check to make sure the class loader has been initialized.
226 */
227 private void check() {
228 if (!initialized) {
229 throw new SecurityException("ClassLoader object not initialized");
230 }
231 }
232
233 }