Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java
38831 views
1
/*
2
* Copyright (c) 1996, 2017, 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.registry;
27
28
import java.util.Enumeration;
29
import java.util.Hashtable;
30
import java.util.MissingResourceException;
31
import java.util.ResourceBundle;
32
import java.io.FilePermission;
33
import java.net.*;
34
import java.rmi.*;
35
import java.rmi.server.ObjID;
36
import java.rmi.server.ServerNotActiveException;
37
import java.rmi.registry.Registry;
38
import java.rmi.server.RMIClientSocketFactory;
39
import java.rmi.server.RMIServerSocketFactory;
40
import java.security.AccessControlContext;
41
import java.security.AccessController;
42
import java.security.CodeSource;
43
import java.security.Policy;
44
import java.security.PrivilegedActionException;
45
import java.security.PrivilegedExceptionAction;
46
import java.security.PermissionCollection;
47
import java.security.Permissions;
48
import java.security.PrivilegedAction;
49
import java.security.ProtectionDomain;
50
import java.security.Security;
51
import java.text.MessageFormat;
52
53
import sun.misc.ObjectInputFilter;
54
55
import sun.rmi.runtime.Log;
56
import sun.rmi.server.UnicastRef;
57
import sun.rmi.server.UnicastServerRef;
58
import sun.rmi.server.UnicastServerRef2;
59
import sun.rmi.transport.LiveRef;
60
61
/**
62
* A "registry" exists on every node that allows RMI connections to
63
* servers on that node. The registry on a particular node contains a
64
* transient database that maps names to remote objects. When the
65
* node boots, the registry database is empty. The names stored in the
66
* registry are pure and are not parsed. A service storing itself in
67
* the registry may want to prefix its name of the service by a package
68
* name (although not required), to reduce name collisions in the
69
* registry.
70
*
71
* The LocateRegistry class is used to obtain registry for different hosts.
72
* <p>
73
* The default RegistryImpl exported restricts access to clients on the local host
74
* for the methods {@link #bind}, {@link #rebind}, {@link #unbind} by checking
75
* the client host in the skeleton.
76
*
77
* @see java.rmi.registry.LocateRegistry
78
*/
79
public class RegistryImpl extends java.rmi.server.RemoteServer
80
implements Registry
81
{
82
83
/* indicate compatibility with JDK 1.1.x version of class */
84
private static final long serialVersionUID = 4666870661827494597L;
85
private Hashtable<String, Remote> bindings
86
= new Hashtable<>(101);
87
private static Hashtable<InetAddress, InetAddress> allowedAccessCache
88
= new Hashtable<>(3);
89
private static RegistryImpl registry;
90
private static ObjID id = new ObjID(ObjID.REGISTRY_ID);
91
92
private static ResourceBundle resources = null;
93
94
/**
95
* Property name of the RMI Registry serial filter to augment
96
* the built-in list of allowed types.
97
* Setting the property in the {@code lib/security/java.security} file
98
* will enable the augmented filter.
99
*/
100
private static final String REGISTRY_FILTER_PROPNAME = "sun.rmi.registry.registryFilter";
101
102
/** Registry max depth of remote invocations. **/
103
private static final int REGISTRY_MAX_DEPTH = 20;
104
105
/** Registry maximum array size in remote invocations. **/
106
private static final int REGISTRY_MAX_ARRAY_SIZE = 1_000_000;
107
108
/**
109
* The registryFilter created from the value of the {@code "sun.rmi.registry.registryFilter"}
110
* property.
111
*/
112
private static final ObjectInputFilter registryFilter =
113
AccessController.doPrivileged((PrivilegedAction<ObjectInputFilter>)RegistryImpl::initRegistryFilter);
114
115
/**
116
* Initialize the registryFilter from the security properties or system property; if any
117
* @return an ObjectInputFilter, or null
118
*/
119
private static ObjectInputFilter initRegistryFilter() {
120
ObjectInputFilter filter = null;
121
String props = System.getProperty(REGISTRY_FILTER_PROPNAME);
122
if (props == null) {
123
props = Security.getProperty(REGISTRY_FILTER_PROPNAME);
124
}
125
if (props != null) {
126
filter = ObjectInputFilter.Config.createFilter2(props);
127
Log regLog = Log.getLog("sun.rmi.registry", "registry", -1);
128
if (regLog.isLoggable(Log.BRIEF)) {
129
regLog.log(Log.BRIEF, "registryFilter = " + filter);
130
}
131
}
132
return filter;
133
}
134
135
/**
136
* Construct a new RegistryImpl on the specified port with the
137
* given custom socket factory pair.
138
*/
139
public RegistryImpl(int port,
140
RMIClientSocketFactory csf,
141
RMIServerSocketFactory ssf)
142
throws RemoteException
143
{
144
this(port, csf, ssf, RegistryImpl::registryFilter);
145
}
146
147
148
/**
149
* Construct a new RegistryImpl on the specified port with the
150
* given custom socket factory pair and ObjectInputFilter.
151
*/
152
public RegistryImpl(int port,
153
RMIClientSocketFactory csf,
154
RMIServerSocketFactory ssf,
155
ObjectInputFilter serialFilter)
156
throws RemoteException
157
{
158
if (port == Registry.REGISTRY_PORT && System.getSecurityManager() != null) {
159
// grant permission for default port only.
160
try {
161
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
162
public Void run() throws RemoteException {
163
LiveRef lref = new LiveRef(id, port, csf, ssf);
164
setup(new UnicastServerRef2(lref, serialFilter));
165
return null;
166
}
167
}, null, new SocketPermission("localhost:"+port, "listen,accept"));
168
} catch (PrivilegedActionException pae) {
169
throw (RemoteException)pae.getException();
170
}
171
} else {
172
LiveRef lref = new LiveRef(id, port, csf, ssf);
173
setup(new UnicastServerRef2(lref, serialFilter));
174
}
175
}
176
177
/**
178
* Construct a new RegistryImpl on the specified port.
179
*/
180
public RegistryImpl(int port)
181
throws RemoteException
182
{
183
if (port == Registry.REGISTRY_PORT && System.getSecurityManager() != null) {
184
// grant permission for default port only.
185
try {
186
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
187
public Void run() throws RemoteException {
188
LiveRef lref = new LiveRef(id, port);
189
setup(new UnicastServerRef(lref, RegistryImpl::registryFilter));
190
return null;
191
}
192
}, null, new SocketPermission("localhost:"+port, "listen,accept"));
193
} catch (PrivilegedActionException pae) {
194
throw (RemoteException)pae.getException();
195
}
196
} else {
197
LiveRef lref = new LiveRef(id, port);
198
setup(new UnicastServerRef(lref, RegistryImpl::registryFilter));
199
}
200
}
201
202
/*
203
* Create the export the object using the parameter
204
* <code>uref</code>
205
*/
206
private void setup(UnicastServerRef uref)
207
throws RemoteException
208
{
209
/* Server ref must be created and assigned before remote
210
* object 'this' can be exported.
211
*/
212
ref = uref;
213
uref.exportObject(this, null, true);
214
}
215
216
/**
217
* Returns the remote object for specified name in the registry.
218
* @exception RemoteException If remote operation failed.
219
* @exception NotBoundException If name is not currently bound.
220
*/
221
public Remote lookup(String name)
222
throws RemoteException, NotBoundException
223
{
224
synchronized (bindings) {
225
Remote obj = bindings.get(name);
226
if (obj == null)
227
throw new NotBoundException(name);
228
return obj;
229
}
230
}
231
232
/**
233
* Binds the name to the specified remote object.
234
* @exception RemoteException If remote operation failed.
235
* @exception AlreadyBoundException If name is already bound.
236
*/
237
public void bind(String name, Remote obj)
238
throws RemoteException, AlreadyBoundException, AccessException
239
{
240
// The access check preventing remote access is done in the skeleton
241
// and is not applicable to local access.
242
synchronized (bindings) {
243
Remote curr = bindings.get(name);
244
if (curr != null)
245
throw new AlreadyBoundException(name);
246
bindings.put(name, obj);
247
}
248
}
249
250
/**
251
* Unbind the name.
252
* @exception RemoteException If remote operation failed.
253
* @exception NotBoundException If name is not currently bound.
254
*/
255
public void unbind(String name)
256
throws RemoteException, NotBoundException, AccessException
257
{
258
// The access check preventing remote access is done in the skeleton
259
// and is not applicable to local access.
260
synchronized (bindings) {
261
Remote obj = bindings.get(name);
262
if (obj == null)
263
throw new NotBoundException(name);
264
bindings.remove(name);
265
}
266
}
267
268
/**
269
* Rebind the name to a new object, replaces any existing binding.
270
* @exception RemoteException If remote operation failed.
271
*/
272
public void rebind(String name, Remote obj)
273
throws RemoteException, AccessException
274
{
275
// The access check preventing remote access is done in the skeleton
276
// and is not applicable to local access.
277
bindings.put(name, obj);
278
}
279
280
/**
281
* Returns an enumeration of the names in the registry.
282
* @exception RemoteException If remote operation failed.
283
*/
284
public String[] list()
285
throws RemoteException
286
{
287
String[] names;
288
synchronized (bindings) {
289
int i = bindings.size();
290
names = new String[i];
291
Enumeration<String> enum_ = bindings.keys();
292
while ((--i) >= 0)
293
names[i] = enum_.nextElement();
294
}
295
return names;
296
}
297
298
/**
299
* Check that the caller has access to perform indicated operation.
300
* The client must be on same the same host as this server.
301
*/
302
public static void checkAccess(String op) throws AccessException {
303
try {
304
/*
305
* Get client host that this registry operation was made from.
306
*/
307
final String clientHostName = getClientHost();
308
InetAddress clientHost;
309
310
try {
311
clientHost = java.security.AccessController.doPrivileged(
312
new java.security.PrivilegedExceptionAction<InetAddress>() {
313
public InetAddress run()
314
throws java.net.UnknownHostException
315
{
316
return InetAddress.getByName(clientHostName);
317
}
318
});
319
} catch (PrivilegedActionException pae) {
320
throw (java.net.UnknownHostException) pae.getException();
321
}
322
323
// if client not yet seen, make sure client allowed access
324
if (allowedAccessCache.get(clientHost) == null) {
325
326
if (clientHost.isAnyLocalAddress()) {
327
throw new AccessException(
328
op + " disallowed; origin unknown");
329
}
330
331
try {
332
final InetAddress finalClientHost = clientHost;
333
334
java.security.AccessController.doPrivileged(
335
new java.security.PrivilegedExceptionAction<Void>() {
336
public Void run() throws java.io.IOException {
337
/*
338
* if a ServerSocket can be bound to the client's
339
* address then that address must be local
340
*/
341
(new ServerSocket(0, 10, finalClientHost)).close();
342
allowedAccessCache.put(finalClientHost,
343
finalClientHost);
344
return null;
345
}
346
});
347
} catch (PrivilegedActionException pae) {
348
// must have been an IOException
349
350
throw new AccessException(
351
op + " disallowed; origin " +
352
clientHost + " is non-local host");
353
}
354
}
355
} catch (ServerNotActiveException ex) {
356
/*
357
* Local call from this VM: allow access.
358
*/
359
} catch (java.net.UnknownHostException ex) {
360
throw new AccessException(op + " disallowed; origin is unknown host");
361
}
362
}
363
364
public static ObjID getID() {
365
return id;
366
}
367
368
/**
369
* Retrieves text resources from the locale-specific properties file.
370
*/
371
private static String getTextResource(String key) {
372
if (resources == null) {
373
try {
374
resources = ResourceBundle.getBundle(
375
"sun.rmi.registry.resources.rmiregistry");
376
} catch (MissingResourceException mre) {
377
}
378
if (resources == null) {
379
// throwing an Error is a bit extreme, methinks
380
return ("[missing resource file: " + key + "]");
381
}
382
}
383
384
String val = null;
385
try {
386
val = resources.getString(key);
387
} catch (MissingResourceException mre) {
388
}
389
390
if (val == null) {
391
return ("[missing resource: " + key + "]");
392
} else {
393
return (val);
394
}
395
}
396
397
/**
398
* ObjectInputFilter to filter Registry input objects.
399
* The list of acceptable classes is limited to classes normally
400
* stored in a registry.
401
*
402
* @param filterInfo access to the class, array length, etc.
403
* @return {@link ObjectInputFilter.Status#ALLOWED} if allowed,
404
* {@link ObjectInputFilter.Status#REJECTED} if rejected,
405
* otherwise {@link ObjectInputFilter.Status#UNDECIDED}
406
*/
407
private static ObjectInputFilter.Status registryFilter(ObjectInputFilter.FilterInfo filterInfo) {
408
if (registryFilter != null) {
409
ObjectInputFilter.Status status = registryFilter.checkInput(filterInfo);
410
if (status != ObjectInputFilter.Status.UNDECIDED) {
411
// The Registry filter can override the built-in white-list
412
return status;
413
}
414
}
415
416
if (filterInfo.depth() > REGISTRY_MAX_DEPTH) {
417
return ObjectInputFilter.Status.REJECTED;
418
}
419
Class<?> clazz = filterInfo.serialClass();
420
if (clazz != null) {
421
if (clazz.isArray()) {
422
// Arrays are REJECTED only if they exceed the limit
423
return (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > REGISTRY_MAX_ARRAY_SIZE)
424
? ObjectInputFilter.Status.REJECTED
425
: ObjectInputFilter.Status.UNDECIDED;
426
}
427
if (String.class == clazz
428
|| java.lang.Number.class.isAssignableFrom(clazz)
429
|| Remote.class.isAssignableFrom(clazz)
430
|| java.lang.reflect.Proxy.class.isAssignableFrom(clazz)
431
|| UnicastRef.class.isAssignableFrom(clazz)
432
|| RMIClientSocketFactory.class.isAssignableFrom(clazz)
433
|| RMIServerSocketFactory.class.isAssignableFrom(clazz)
434
|| java.rmi.activation.ActivationID.class.isAssignableFrom(clazz)
435
|| java.rmi.server.UID.class.isAssignableFrom(clazz)) {
436
return ObjectInputFilter.Status.ALLOWED;
437
} else {
438
return ObjectInputFilter.Status.REJECTED;
439
}
440
}
441
return ObjectInputFilter.Status.UNDECIDED;
442
}
443
444
/**
445
* Main program to start a registry. <br>
446
* The port number can be specified on the command line.
447
*/
448
public static void main(String args[])
449
{
450
// Create and install the security manager if one is not installed
451
// already.
452
if (System.getSecurityManager() == null) {
453
System.setSecurityManager(new RMISecurityManager());
454
}
455
456
try {
457
/*
458
* Fix bugid 4147561: When JDK tools are executed, the value of
459
* the CLASSPATH environment variable for the shell in which they
460
* were invoked is no longer incorporated into the application
461
* class path; CLASSPATH's only effect is to be the value of the
462
* system property "env.class.path". To preserve the previous
463
* (JDK1.1 and JDK1.2beta3) behavior of this tool, however, its
464
* CLASSPATH should still be considered when resolving classes
465
* being unmarshalled. To effect this old behavior, a class
466
* loader that loads from the file path specified in the
467
* "env.class.path" property is created and set to be the context
468
* class loader before the remote object is exported.
469
*/
470
String envcp = System.getProperty("env.class.path");
471
if (envcp == null) {
472
envcp = "."; // preserve old default behavior
473
}
474
URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp);
475
ClassLoader cl = new URLClassLoader(urls);
476
477
/*
478
* Fix bugid 4242317: Classes defined by this class loader should
479
* be annotated with the value of the "java.rmi.server.codebase"
480
* property, not the "file:" URLs for the CLASSPATH elements.
481
*/
482
sun.rmi.server.LoaderHandler.registerCodebaseLoader(cl);
483
484
Thread.currentThread().setContextClassLoader(cl);
485
486
final int regPort = (args.length >= 1) ? Integer.parseInt(args[0])
487
: Registry.REGISTRY_PORT;
488
try {
489
registry = AccessController.doPrivileged(
490
new PrivilegedExceptionAction<RegistryImpl>() {
491
public RegistryImpl run() throws RemoteException {
492
return new RegistryImpl(regPort);
493
}
494
}, getAccessControlContext(regPort));
495
} catch (PrivilegedActionException ex) {
496
throw (RemoteException) ex.getException();
497
}
498
499
// prevent registry from exiting
500
while (true) {
501
try {
502
Thread.sleep(Long.MAX_VALUE);
503
} catch (InterruptedException e) {
504
}
505
}
506
} catch (NumberFormatException e) {
507
System.err.println(MessageFormat.format(
508
getTextResource("rmiregistry.port.badnumber"),
509
args[0] ));
510
System.err.println(MessageFormat.format(
511
getTextResource("rmiregistry.usage"),
512
"rmiregistry" ));
513
} catch (Exception e) {
514
e.printStackTrace();
515
}
516
System.exit(1);
517
}
518
519
/**
520
* Generates an AccessControlContext with minimal permissions.
521
* The approach used here is taken from the similar method
522
* getAccessControlContext() in the sun.applet.AppletPanel class.
523
*/
524
private static AccessControlContext getAccessControlContext(int port) {
525
// begin with permissions granted to all code in current policy
526
PermissionCollection perms = AccessController.doPrivileged(
527
new java.security.PrivilegedAction<PermissionCollection>() {
528
public PermissionCollection run() {
529
CodeSource codesource = new CodeSource(null,
530
(java.security.cert.Certificate[]) null);
531
Policy p = java.security.Policy.getPolicy();
532
if (p != null) {
533
return p.getPermissions(codesource);
534
} else {
535
return new Permissions();
536
}
537
}
538
});
539
540
/*
541
* Anyone can connect to the registry and the registry can connect
542
* to and possibly download stubs from anywhere. Downloaded stubs and
543
* related classes themselves are more tightly limited by RMI.
544
*/
545
perms.add(new SocketPermission("*", "connect,accept"));
546
perms.add(new SocketPermission("localhost:"+port, "listen,accept"));
547
548
perms.add(new RuntimePermission("accessClassInPackage.sun.jvmstat.*"));
549
perms.add(new RuntimePermission("accessClassInPackage.sun.jvm.hotspot.*"));
550
551
perms.add(new FilePermission("<<ALL FILES>>", "read"));
552
553
/*
554
* Create an AccessControlContext that consists of a single
555
* protection domain with only the permissions calculated above.
556
*/
557
ProtectionDomain pd = new ProtectionDomain(
558
new CodeSource(null,
559
(java.security.cert.Certificate[]) null), perms);
560
return new AccessControlContext(new ProtectionDomain[] { pd });
561
}
562
}
563
564