1 /* 2 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.rmi.server; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.ObjectInputStream; 31 import java.io.ObjectStreamClass; 32 import java.io.StreamCorruptedException; 33 import java.net.URL; 34 import java.util.*; 35 import java.security.AccessControlException; 36 import java.security.Permission; 37 38 import java.rmi.server.RMIClassLoader; 39 import java.security.PrivilegedAction; 40 41 /** 42 * MarshalInputStream is an extension of ObjectInputStream. When resolving 43 * a class, it reads an object from the stream written by a corresponding 44 * MarshalOutputStream. If the class to be resolved is not available 45 * locally, from the first class loader on the execution stack, or from the 46 * context class loader of the current thread, it will attempt to load the 47 * class from the location annotated by the sending MarshalOutputStream. 48 * This location object must be a string representing a path of URLs. 49 * 50 * A new MarshalInputStream should be created to deserialize remote objects or 51 * graphs containing remote objects. Objects are created from the stream 52 * using the ObjectInputStream.readObject method. 53 * 54 * @author Peter Jones 55 */ 56 public class MarshalInputStream extends ObjectInputStream { 57 58 /** 59 * Value of "java.rmi.server.useCodebaseOnly" property, 60 * as cached at class initialization time. 61 * 62 * The default value is true. That is, the value is true 63 * if the property is absent or is not equal to "false". 64 * The value is only false when the property is present 65 * and is equal to "false". 66 */ 67 private static final boolean useCodebaseOnlyProperty = 68 ! java.security.AccessController.doPrivileged( 69 (PrivilegedAction<String>) () -> System.getProperty( 70 "java.rmi.server.useCodebaseOnly", "true")) 71 .equalsIgnoreCase("false"); 72 73 /** table to hold sun classes to which access is explicitly permitted */ 74 protected static Map<String, Class<?>> permittedSunClasses 75 = new HashMap<>(3); 76 77 /** if true, don't try superclass first in resolveClass() */ 78 private boolean skipDefaultResolveClass = false; 79 80 /** callbacks to make when done() called: maps Object to Runnable */ 81 private final Map<Object, Runnable> doneCallbacks 82 = new HashMap<>(3); 83 84 /** 85 * if true, load classes (if not available locally) only from the 86 * URL specified by the "java.rmi.server.codebase" property. 87 */ 88 private boolean useCodebaseOnly = useCodebaseOnlyProperty; 89 90 /* 91 * Fix for 4179055: The remote object services inside the 92 * activation daemon use stubs that are in the package 93 * sun.rmi.server. Classes for these stubs should be loaded from 94 * the classpath by RMI system code and not by the normal 95 * unmarshalling process as applications should not need to have 96 * permission to access the sun implementation classes. 97 * 98 * Note: this fix should be redone when API changes may be 99 * integrated 100 * 101 * During parameter unmarshalling RMI needs to explicitly permit 102 * access to three sun.* stub classes 103 */ 104 static { 105 try { 106 String system = 107 "sun.rmi.server.Activation$ActivationSystemImpl_Stub"; 108 String registry = "sun.rmi.registry.RegistryImpl_Stub"; 109 110 permittedSunClasses.put(system, Class.forName(system)); 111 permittedSunClasses.put(registry, Class.forName(registry)); 112 113 } catch (ClassNotFoundException e) { 114 throw new NoClassDefFoundError("Missing system class: " + 115 e.getMessage()); 116 } 117 } 118 119 /** 120 * Create a new MarshalInputStream object. 121 */ 122 public MarshalInputStream(InputStream in) 123 throws IOException, StreamCorruptedException 124 { 125 super(in); 126 } 127 128 /** 129 * Returns a callback previously registered via the setDoneCallback 130 * method with given key, or null if no callback has yet been registered 131 * with that key. 132 */ 133 public Runnable getDoneCallback(Object key) { 134 return doneCallbacks.get(key); // not thread-safe 135 } 136 137 /** 138 * Registers a callback to make when this stream's done() method is 139 * invoked, along with a key for retrieving the same callback instance 140 * subsequently from the getDoneCallback method. 141 */ 142 public void setDoneCallback(Object key, Runnable callback) { 143 //assert(!doneCallbacks.contains(key)); 144 doneCallbacks.put(key, callback); // not thread-safe 145 } 146 147 /** 148 * Indicates that the user of this MarshalInputStream is done reading 149 * objects from it, so all callbacks registered with the setDoneCallback 150 * method should now be (synchronously) executed. When this method 151 * returns, there are no more callbacks registered. 152 * 153 * This method is implicitly invoked by close() before it delegates to 154 * the superclass's close method. 155 */ 156 public void done() { 157 Iterator<Runnable> iter = doneCallbacks.values().iterator(); 158 while (iter.hasNext()) { // not thread-safe 159 Runnable callback = iter.next(); 160 callback.run(); 161 } 162 doneCallbacks.clear(); 163 } 164 165 /** 166 * Closes this stream, implicitly invoking done() first. 167 */ 168 public void close() throws IOException { 169 done(); 170 super.close(); 171 } 172 173 /** 174 * resolveClass is extended to acquire (if present) the location 175 * from which to load the specified class. 176 * It will find, load, and return the class. 177 */ 178 protected Class<?> resolveClass(ObjectStreamClass classDesc) 179 throws IOException, ClassNotFoundException 180 { 181 /* 182 * Always read annotation written by MarshalOutputStream 183 * describing where to load class from. 184 */ 185 Object annotation = readLocation(); 186 187 String className = classDesc.getName(); 188 189 /* 190 * Unless we were told to skip this consideration, choose the 191 * "default loader" to simulate the default ObjectInputStream 192 * resolveClass mechanism (that is, choose the first non-null 193 * loader on the execution stack) to maximize the likelihood of 194 * type compatibility with calling code. (This consideration 195 * is skipped during server parameter unmarshalling using the 1.2 196 * stub protocol, because there would never be a non-null class 197 * loader on the stack in that situation anyway.) 198 */ 199 ClassLoader defaultLoader = 200 skipDefaultResolveClass ? null : latestUserDefinedLoader(); 201 202 /* 203 * If the "java.rmi.server.useCodebaseOnly" property was true or 204 * useCodebaseOnly() was called or the annotation is not a String, 205 * load from the local loader using the "java.rmi.server.codebase" 206 * URL. Otherwise, load from a loader using the codebase URL in 207 * the annotation. 208 */ 209 String codebase = null; 210 if (!useCodebaseOnly && annotation instanceof String) { 211 codebase = (String) annotation; 212 } 213 214 try { 215 return RMIClassLoader.loadClass(codebase, className, 216 defaultLoader); 217 } catch (AccessControlException e) { 218 return checkSunClass(className, e); 219 } catch (ClassNotFoundException e) { 220 /* 221 * Fix for 4442373: delegate to ObjectInputStream.resolveClass() 222 * to resolve primitive classes. 223 */ 224 try { 225 if (Character.isLowerCase(className.charAt(0)) && 226 className.indexOf('.') == -1) 227 { 228 return super.resolveClass(classDesc); 229 } 230 } catch (ClassNotFoundException e2) { 231 } 232 throw e; 233 } 234 } 235 236 /** 237 * resolveProxyClass is extended to acquire (if present) the location 238 * to determine the class loader to define the proxy class in. 239 */ 240 protected Class<?> resolveProxyClass(String[] interfaces) 241 throws IOException, ClassNotFoundException 242 { 243 /* 244 * Always read annotation written by MarshalOutputStream. 245 */ 246 Object annotation = readLocation(); 247 248 ClassLoader defaultLoader = 249 skipDefaultResolveClass ? null : latestUserDefinedLoader(); 250 251 String codebase = null; 252 if (!useCodebaseOnly && annotation instanceof String) { 253 codebase = (String) annotation; 254 } 255 256 return RMIClassLoader.loadProxyClass(codebase, interfaces, 257 defaultLoader); 258 } 259 260 /* 261 * Returns the first non-null class loader up the execution stack, or null 262 * if only code from the null class loader is on the stack. 263 */ 264 private static ClassLoader latestUserDefinedLoader() { 265 return sun.misc.VM.latestUserDefinedLoader(); 266 } 267 268 /** 269 * Fix for 4179055: Need to assist resolving sun stubs; resolve 270 * class locally if it is a "permitted" sun class 271 */ 272 private Class<?> checkSunClass(String className, AccessControlException e) 273 throws AccessControlException 274 { 275 // ensure that we are giving out a stub for the correct reason 276 Permission perm = e.getPermission(); 277 String name = null; 278 if (perm != null) { 279 name = perm.getName(); 280 } 281 282 Class<?> resolvedClass = permittedSunClasses.get(className); 283 284 // if class not permitted, throw the SecurityException 285 if ((name == null) || 286 (resolvedClass == null) || 287 ((!name.equals("accessClassInPackage.sun.rmi.server")) && 288 (!name.equals("accessClassInPackage.sun.rmi.registry")))) 289 { 290 throw e; 291 } 292 293 return resolvedClass; 294 } 295 296 /** 297 * Return the location for the class in the stream. This method can 298 * be overridden by subclasses that store this annotation somewhere 299 * else than as the next object in the stream, as is done by this class. 300 */ 301 protected Object readLocation() 302 throws IOException, ClassNotFoundException 303 { 304 return readObject(); 305 } 306 307 /** 308 * Set a flag to indicate that the superclass's default resolveClass() 309 * implementation should not be invoked by our resolveClass(). 310 */ 311 void skipDefaultResolveClass() { 312 skipDefaultResolveClass = true; 313 } 314 315 /** 316 * Disable code downloading except from the URL specified by the 317 * "java.rmi.server.codebase" property. 318 */ 319 void useCodebaseOnly() { 320 useCodebaseOnly = true; 321 } 322 }