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 }