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