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