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