Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/sun/rmi/registry/RegistryImpl.java
+++ new/src/share/classes/sun/rmi/registry/RegistryImpl.java
1 1 /*
2 2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 package sun.rmi.registry;
27 27
28 28 import java.util.Enumeration;
29 29 import java.util.Hashtable;
30 30 import java.util.MissingResourceException;
31 31 import java.util.ResourceBundle;
32 32 import java.io.FilePermission;
33 33 import java.io.IOException;
34 34 import java.net.*;
35 35 import java.rmi.*;
36 36 import java.rmi.server.ObjID;
37 37 import java.rmi.server.RemoteServer;
38 38 import java.rmi.server.ServerNotActiveException;
39 39 import java.rmi.registry.Registry;
40 40 import java.rmi.server.RMIClientSocketFactory;
41 41 import java.rmi.server.RMIServerSocketFactory;
42 42 import java.security.AccessControlContext;
43 43 import java.security.AccessController;
44 44 import java.security.CodeSource;
45 45 import java.security.Policy;
46 46 import java.security.PrivilegedActionException;
47 47 import java.security.PrivilegedExceptionAction;
48 48 import java.security.PermissionCollection;
49 49 import java.security.Permissions;
50 50 import java.security.ProtectionDomain;
51 51 import java.text.MessageFormat;
52 52 import sun.rmi.server.LoaderHandler;
53 53 import sun.rmi.server.UnicastServerRef;
54 54 import sun.rmi.server.UnicastServerRef2;
55 55 import sun.rmi.transport.LiveRef;
56 56 import sun.rmi.transport.ObjectTable;
57 57 import sun.rmi.transport.Target;
58 58
59 59 /**
60 60 * A "registry" exists on every node that allows RMI connections to
61 61 * servers on that node. The registry on a particular node contains a
62 62 * transient database that maps names to remote objects. When the
63 63 * node boots, the registry database is empty. The names stored in the
64 64 * registry are pure and are not parsed. A service storing itself in
65 65 * the registry may want to prefix its name of the service by a package
66 66 * name (although not required), to reduce name collisions in the
67 67 * registry.
68 68 *
69 69 * The LocateRegistry class is used to obtain registry for different hosts.
↓ open down ↓ |
69 lines elided |
↑ open up ↑ |
70 70 *
71 71 * @see java.rmi.registry.LocateRegistry
72 72 */
73 73 public class RegistryImpl extends java.rmi.server.RemoteServer
74 74 implements Registry
75 75 {
76 76
77 77 /* indicate compatibility with JDK 1.1.x version of class */
78 78 private static final long serialVersionUID = 4666870661827494597L;
79 79 private Hashtable<String, Remote> bindings
80 - = new Hashtable<String, Remote>(101);
80 + = new Hashtable<>(101);
81 81 private static Hashtable<InetAddress, InetAddress> allowedAccessCache
82 - = new Hashtable<InetAddress, InetAddress>(3);
82 + = new Hashtable<>(3);
83 83 private static RegistryImpl registry;
84 84 private static ObjID id = new ObjID(ObjID.REGISTRY_ID);
85 85
86 86 private static ResourceBundle resources = null;
87 87
88 88 /**
89 89 * Construct a new RegistryImpl on the specified port with the
90 90 * given custom socket factory pair.
91 91 */
92 92 public RegistryImpl(int port,
93 93 RMIClientSocketFactory csf,
94 94 RMIServerSocketFactory ssf)
95 95 throws RemoteException
96 96 {
97 97 LiveRef lref = new LiveRef(id, port, csf, ssf);
98 98 setup(new UnicastServerRef2(lref));
99 99 }
100 100
101 101 /**
102 102 * Construct a new RegistryImpl on the specified port.
103 103 */
104 104 public RegistryImpl(int port)
105 105 throws RemoteException
106 106 {
107 107 LiveRef lref = new LiveRef(id, port);
108 108 setup(new UnicastServerRef(lref));
109 109 }
110 110
111 111 /*
112 112 * Create the export the object using the parameter
113 113 * <code>uref</code>
114 114 */
115 115 private void setup(UnicastServerRef uref)
116 116 throws RemoteException
117 117 {
118 118 /* Server ref must be created and assigned before remote
119 119 * object 'this' can be exported.
120 120 */
121 121 ref = uref;
122 122 uref.exportObject(this, null, true);
123 123 }
124 124
125 125 /**
126 126 * Returns the remote object for specified name in the registry.
127 127 * @exception RemoteException If remote operation failed.
128 128 * @exception NotBound If name is not currently bound.
129 129 */
130 130 public Remote lookup(String name)
131 131 throws RemoteException, NotBoundException
132 132 {
133 133 synchronized (bindings) {
134 134 Remote obj = bindings.get(name);
135 135 if (obj == null)
136 136 throw new NotBoundException(name);
137 137 return obj;
138 138 }
139 139 }
140 140
141 141 /**
142 142 * Binds the name to the specified remote object.
143 143 * @exception RemoteException If remote operation failed.
144 144 * @exception AlreadyBoundException If name is already bound.
145 145 */
146 146 public void bind(String name, Remote obj)
147 147 throws RemoteException, AlreadyBoundException, AccessException
148 148 {
149 149 checkAccess("Registry.bind");
150 150 synchronized (bindings) {
151 151 Remote curr = bindings.get(name);
152 152 if (curr != null)
153 153 throw new AlreadyBoundException(name);
154 154 bindings.put(name, obj);
155 155 }
156 156 }
157 157
158 158 /**
159 159 * Unbind the name.
160 160 * @exception RemoteException If remote operation failed.
161 161 * @exception NotBound If name is not currently bound.
162 162 */
163 163 public void unbind(String name)
164 164 throws RemoteException, NotBoundException, AccessException
165 165 {
166 166 checkAccess("Registry.unbind");
167 167 synchronized (bindings) {
168 168 Remote obj = bindings.get(name);
169 169 if (obj == null)
170 170 throw new NotBoundException(name);
171 171 bindings.remove(name);
172 172 }
173 173 }
174 174
175 175 /**
176 176 * Rebind the name to a new object, replaces any existing binding.
177 177 * @exception RemoteException If remote operation failed.
178 178 */
179 179 public void rebind(String name, Remote obj)
180 180 throws RemoteException, AccessException
181 181 {
182 182 checkAccess("Registry.rebind");
183 183 bindings.put(name, obj);
184 184 }
185 185
186 186 /**
↓ open down ↓ |
94 lines elided |
↑ open up ↑ |
187 187 * Returns an enumeration of the names in the registry.
188 188 * @exception RemoteException If remote operation failed.
189 189 */
190 190 public String[] list()
191 191 throws RemoteException
192 192 {
193 193 String[] names;
194 194 synchronized (bindings) {
195 195 int i = bindings.size();
196 196 names = new String[i];
197 - Enumeration enum_ = bindings.keys();
197 + Enumeration<String> enum_ = bindings.keys();
198 198 while ((--i) >= 0)
199 - names[i] = (String)enum_.nextElement();
199 + names[i] = enum_.nextElement();
200 200 }
201 201 return names;
202 202 }
203 203
204 204 /**
205 205 * Check that the caller has access to perform indicated operation.
206 206 * The client must be on same the same host as this server.
207 207 */
208 208 public static void checkAccess(String op) throws AccessException {
209 209
210 210 try {
211 211 /*
212 212 * Get client host that this registry operation was made from.
213 213 */
214 214 final String clientHostName = getClientHost();
215 215 InetAddress clientHost;
216 216
217 217 try {
218 218 clientHost = java.security.AccessController.doPrivileged(
219 219 new java.security.PrivilegedExceptionAction<InetAddress>() {
220 220 public InetAddress run()
221 221 throws java.net.UnknownHostException
222 222 {
223 223 return InetAddress.getByName(clientHostName);
224 224 }
225 225 });
226 226 } catch (PrivilegedActionException pae) {
227 227 throw (java.net.UnknownHostException) pae.getException();
228 228 }
229 229
230 230 // if client not yet seen, make sure client allowed access
231 231 if (allowedAccessCache.get(clientHost) == null) {
232 232
233 233 if (clientHost.isAnyLocalAddress()) {
234 234 throw new AccessException(
235 235 "Registry." + op + " disallowed; origin unknown");
236 236 }
237 237
238 238 try {
239 239 final InetAddress finalClientHost = clientHost;
240 240
241 241 java.security.AccessController.doPrivileged(
242 242 new java.security.PrivilegedExceptionAction<Void>() {
243 243 public Void run() throws java.io.IOException {
244 244 /*
245 245 * if a ServerSocket can be bound to the client's
246 246 * address then that address must be local
247 247 */
248 248 (new ServerSocket(0, 10, finalClientHost)).close();
249 249 allowedAccessCache.put(finalClientHost,
250 250 finalClientHost);
251 251 return null;
252 252 }
253 253 });
254 254 } catch (PrivilegedActionException pae) {
255 255 // must have been an IOException
256 256
257 257 throw new AccessException(
258 258 "Registry." + op + " disallowed; origin " +
259 259 clientHost + " is non-local host");
260 260 }
261 261 }
262 262 } catch (ServerNotActiveException ex) {
263 263 /*
264 264 * Local call from this VM: allow access.
265 265 */
266 266 } catch (java.net.UnknownHostException ex) {
267 267 throw new AccessException("Registry." + op +
268 268 " disallowed; origin is unknown host");
269 269 }
270 270 }
271 271
272 272 public static ObjID getID() {
273 273 return id;
274 274 }
275 275
276 276 /**
277 277 * Retrieves text resources from the locale-specific properties file.
278 278 */
279 279 private static String getTextResource(String key) {
280 280 if (resources == null) {
281 281 try {
282 282 resources = ResourceBundle.getBundle(
283 283 "sun.rmi.registry.resources.rmiregistry");
284 284 } catch (MissingResourceException mre) {
285 285 }
286 286 if (resources == null) {
287 287 // throwing an Error is a bit extreme, methinks
288 288 return ("[missing resource file: " + key + "]");
289 289 }
290 290 }
291 291
292 292 String val = null;
293 293 try {
294 294 val = resources.getString(key);
295 295 } catch (MissingResourceException mre) {
296 296 }
297 297
298 298 if (val == null) {
299 299 return ("[missing resource: " + key + "]");
300 300 } else {
301 301 return (val);
302 302 }
303 303 }
304 304
305 305 /**
306 306 * Main program to start a registry. <br>
307 307 * The port number can be specified on the command line.
308 308 */
309 309 public static void main(String args[])
310 310 {
311 311 // Create and install the security manager if one is not installed
312 312 // already.
313 313 if (System.getSecurityManager() == null) {
314 314 System.setSecurityManager(new RMISecurityManager());
315 315 }
316 316
317 317 try {
318 318 /*
319 319 * Fix bugid 4147561: When JDK tools are executed, the value of
320 320 * the CLASSPATH environment variable for the shell in which they
321 321 * were invoked is no longer incorporated into the application
322 322 * class path; CLASSPATH's only effect is to be the value of the
323 323 * system property "env.class.path". To preserve the previous
324 324 * (JDK1.1 and JDK1.2beta3) behavior of this tool, however, its
325 325 * CLASSPATH should still be considered when resolving classes
326 326 * being unmarshalled. To effect this old behavior, a class
327 327 * loader that loads from the file path specified in the
328 328 * "env.class.path" property is created and set to be the context
329 329 * class loader before the remote object is exported.
330 330 */
331 331 String envcp = System.getProperty("env.class.path");
332 332 if (envcp == null) {
333 333 envcp = "."; // preserve old default behavior
334 334 }
335 335 URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp);
336 336 ClassLoader cl = new URLClassLoader(urls);
337 337
338 338 /*
339 339 * Fix bugid 4242317: Classes defined by this class loader should
340 340 * be annotated with the value of the "java.rmi.server.codebase"
341 341 * property, not the "file:" URLs for the CLASSPATH elements.
342 342 */
343 343 sun.rmi.server.LoaderHandler.registerCodebaseLoader(cl);
344 344
345 345 Thread.currentThread().setContextClassLoader(cl);
346 346
347 347 final int regPort = (args.length >= 1) ? Integer.parseInt(args[0])
348 348 : Registry.REGISTRY_PORT;
349 349 try {
350 350 registry = AccessController.doPrivileged(
351 351 new PrivilegedExceptionAction<RegistryImpl>() {
352 352 public RegistryImpl run() throws RemoteException {
353 353 return new RegistryImpl(regPort);
354 354 }
355 355 }, getAccessControlContext());
356 356 } catch (PrivilegedActionException ex) {
357 357 throw (RemoteException) ex.getException();
358 358 }
359 359
360 360 // prevent registry from exiting
361 361 while (true) {
362 362 try {
363 363 Thread.sleep(Long.MAX_VALUE);
364 364 } catch (InterruptedException e) {
365 365 }
366 366 }
367 367 } catch (NumberFormatException e) {
368 368 System.err.println(MessageFormat.format(
369 369 getTextResource("rmiregistry.port.badnumber"),
370 370 args[0] ));
371 371 System.err.println(MessageFormat.format(
372 372 getTextResource("rmiregistry.usage"),
373 373 "rmiregistry" ));
374 374 } catch (Exception e) {
375 375 e.printStackTrace();
376 376 }
377 377 System.exit(1);
378 378 }
379 379
380 380 /**
381 381 * Generates an AccessControlContext with minimal permissions.
382 382 * The approach used here is taken from the similar method
383 383 * getAccessControlContext() in the sun.applet.AppletPanel class.
384 384 */
385 385 private static AccessControlContext getAccessControlContext() {
386 386 // begin with permissions granted to all code in current policy
387 387 PermissionCollection perms = AccessController.doPrivileged(
388 388 new java.security.PrivilegedAction<PermissionCollection>() {
389 389 public PermissionCollection run() {
390 390 CodeSource codesource = new CodeSource(null,
391 391 (java.security.cert.Certificate[]) null);
392 392 Policy p = java.security.Policy.getPolicy();
393 393 if (p != null) {
394 394 return p.getPermissions(codesource);
395 395 } else {
396 396 return new Permissions();
397 397 }
398 398 }
399 399 });
400 400
401 401 /*
402 402 * Anyone can connect to the registry and the registry can connect
403 403 * to and possibly download stubs from anywhere. Downloaded stubs and
404 404 * related classes themselves are more tightly limited by RMI.
405 405 */
406 406 perms.add(new SocketPermission("*", "connect,accept"));
407 407
408 408 perms.add(new RuntimePermission("accessClassInPackage.sun.*"));
409 409
410 410 perms.add(new FilePermission("<<ALL FILES>>", "read"));
411 411
412 412 /*
413 413 * Create an AccessControlContext that consists of a single
414 414 * protection domain with only the permissions calculated above.
415 415 */
416 416 ProtectionDomain pd = new ProtectionDomain(
417 417 new CodeSource(null,
418 418 (java.security.cert.Certificate[]) null), perms);
419 419 return new AccessControlContext(new ProtectionDomain[] { pd });
420 420 }
421 421 }
↓ open down ↓ |
212 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX