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