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