0N/A/*
4483N/A * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.rmi.registry;
0N/A
0N/Aimport java.util.Enumeration;
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.MissingResourceException;
0N/Aimport java.util.ResourceBundle;
4483N/Aimport java.io.FilePermission;
0N/Aimport java.io.IOException;
0N/Aimport java.net.*;
0N/Aimport java.rmi.*;
0N/Aimport java.rmi.server.ObjID;
0N/Aimport java.rmi.server.RemoteServer;
0N/Aimport java.rmi.server.ServerNotActiveException;
0N/Aimport java.rmi.registry.Registry;
0N/Aimport java.rmi.server.RMIClientSocketFactory;
0N/Aimport java.rmi.server.RMIServerSocketFactory;
4455N/Aimport java.security.AccessControlContext;
4455N/Aimport java.security.AccessController;
4455N/Aimport java.security.CodeSource;
4455N/Aimport java.security.Policy;
0N/Aimport java.security.PrivilegedActionException;
4455N/Aimport java.security.PrivilegedExceptionAction;
4455N/Aimport java.security.PermissionCollection;
4455N/Aimport java.security.Permissions;
4455N/Aimport java.security.ProtectionDomain;
0N/Aimport java.text.MessageFormat;
4455N/Aimport sun.rmi.server.LoaderHandler;
0N/Aimport sun.rmi.server.UnicastServerRef;
0N/Aimport sun.rmi.server.UnicastServerRef2;
0N/Aimport sun.rmi.transport.LiveRef;
0N/Aimport sun.rmi.transport.ObjectTable;
0N/Aimport sun.rmi.transport.Target;
0N/A
0N/A/**
0N/A * A "registry" exists on every node that allows RMI connections to
0N/A * servers on that node. The registry on a particular node contains a
0N/A * transient database that maps names to remote objects. When the
0N/A * node boots, the registry database is empty. The names stored in the
0N/A * registry are pure and are not parsed. A service storing itself in
0N/A * the registry may want to prefix its name of the service by a package
0N/A * name (although not required), to reduce name collisions in the
0N/A * registry.
0N/A *
0N/A * The LocateRegistry class is used to obtain registry for different hosts.
0N/A *
0N/A * @see java.rmi.registry.LocateRegistry
0N/A */
0N/Apublic class RegistryImpl extends java.rmi.server.RemoteServer
0N/A implements Registry
0N/A{
0N/A
0N/A /* indicate compatibility with JDK 1.1.x version of class */
0N/A private static final long serialVersionUID = 4666870661827494597L;
28N/A private Hashtable<String, Remote> bindings
5559N/A = new Hashtable<>(101);
28N/A private static Hashtable<InetAddress, InetAddress> allowedAccessCache
5559N/A = new Hashtable<>(3);
0N/A private static RegistryImpl registry;
0N/A private static ObjID id = new ObjID(ObjID.REGISTRY_ID);
0N/A
0N/A private static ResourceBundle resources = null;
0N/A
0N/A /**
0N/A * Construct a new RegistryImpl on the specified port with the
0N/A * given custom socket factory pair.
0N/A */
0N/A public RegistryImpl(int port,
0N/A RMIClientSocketFactory csf,
0N/A RMIServerSocketFactory ssf)
0N/A throws RemoteException
0N/A {
0N/A LiveRef lref = new LiveRef(id, port, csf, ssf);
0N/A setup(new UnicastServerRef2(lref));
0N/A }
0N/A
0N/A /**
0N/A * Construct a new RegistryImpl on the specified port.
0N/A */
0N/A public RegistryImpl(int port)
0N/A throws RemoteException
0N/A {
0N/A LiveRef lref = new LiveRef(id, port);
0N/A setup(new UnicastServerRef(lref));
0N/A }
0N/A
0N/A /*
0N/A * Create the export the object using the parameter
0N/A * <code>uref</code>
0N/A */
0N/A private void setup(UnicastServerRef uref)
0N/A throws RemoteException
0N/A {
0N/A /* Server ref must be created and assigned before remote
0N/A * object 'this' can be exported.
0N/A */
0N/A ref = uref;
0N/A uref.exportObject(this, null, true);
0N/A }
0N/A
0N/A /**
0N/A * Returns the remote object for specified name in the registry.
0N/A * @exception RemoteException If remote operation failed.
0N/A * @exception NotBound If name is not currently bound.
0N/A */
0N/A public Remote lookup(String name)
0N/A throws RemoteException, NotBoundException
0N/A {
0N/A synchronized (bindings) {
28N/A Remote obj = bindings.get(name);
0N/A if (obj == null)
0N/A throw new NotBoundException(name);
0N/A return obj;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Binds the name to the specified remote object.
0N/A * @exception RemoteException If remote operation failed.
0N/A * @exception AlreadyBoundException If name is already bound.
0N/A */
0N/A public void bind(String name, Remote obj)
0N/A throws RemoteException, AlreadyBoundException, AccessException
0N/A {
0N/A checkAccess("Registry.bind");
0N/A synchronized (bindings) {
28N/A Remote curr = bindings.get(name);
0N/A if (curr != null)
0N/A throw new AlreadyBoundException(name);
0N/A bindings.put(name, obj);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Unbind the name.
0N/A * @exception RemoteException If remote operation failed.
0N/A * @exception NotBound If name is not currently bound.
0N/A */
0N/A public void unbind(String name)
0N/A throws RemoteException, NotBoundException, AccessException
0N/A {
0N/A checkAccess("Registry.unbind");
0N/A synchronized (bindings) {
28N/A Remote obj = bindings.get(name);
0N/A if (obj == null)
0N/A throw new NotBoundException(name);
0N/A bindings.remove(name);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Rebind the name to a new object, replaces any existing binding.
0N/A * @exception RemoteException If remote operation failed.
0N/A */
0N/A public void rebind(String name, Remote obj)
0N/A throws RemoteException, AccessException
0N/A {
0N/A checkAccess("Registry.rebind");
0N/A bindings.put(name, obj);
0N/A }
0N/A
0N/A /**
0N/A * Returns an enumeration of the names in the registry.
0N/A * @exception RemoteException If remote operation failed.
0N/A */
0N/A public String[] list()
0N/A throws RemoteException
0N/A {
0N/A String[] names;
0N/A synchronized (bindings) {
0N/A int i = bindings.size();
0N/A names = new String[i];
5559N/A Enumeration<String> enum_ = bindings.keys();
0N/A while ((--i) >= 0)
5559N/A names[i] = enum_.nextElement();
0N/A }
0N/A return names;
0N/A }
0N/A
0N/A /**
0N/A * Check that the caller has access to perform indicated operation.
0N/A * The client must be on same the same host as this server.
0N/A */
0N/A public static void checkAccess(String op) throws AccessException {
0N/A
0N/A try {
0N/A /*
0N/A * Get client host that this registry operation was made from.
0N/A */
0N/A final String clientHostName = getClientHost();
0N/A InetAddress clientHost;
0N/A
0N/A try {
28N/A clientHost = java.security.AccessController.doPrivileged(
28N/A new java.security.PrivilegedExceptionAction<InetAddress>() {
28N/A public InetAddress run()
0N/A throws java.net.UnknownHostException
0N/A {
0N/A return InetAddress.getByName(clientHostName);
0N/A }
0N/A });
0N/A } catch (PrivilegedActionException pae) {
0N/A throw (java.net.UnknownHostException) pae.getException();
0N/A }
0N/A
0N/A // if client not yet seen, make sure client allowed access
0N/A if (allowedAccessCache.get(clientHost) == null) {
0N/A
0N/A if (clientHost.isAnyLocalAddress()) {
0N/A throw new AccessException(
0N/A "Registry." + op + " disallowed; origin unknown");
0N/A }
0N/A
0N/A try {
0N/A final InetAddress finalClientHost = clientHost;
0N/A
0N/A java.security.AccessController.doPrivileged(
28N/A new java.security.PrivilegedExceptionAction<Void>() {
28N/A public Void run() throws java.io.IOException {
0N/A /*
0N/A * if a ServerSocket can be bound to the client's
0N/A * address then that address must be local
0N/A */
0N/A (new ServerSocket(0, 10, finalClientHost)).close();
0N/A allowedAccessCache.put(finalClientHost,
0N/A finalClientHost);
0N/A return null;
0N/A }
0N/A });
0N/A } catch (PrivilegedActionException pae) {
0N/A // must have been an IOException
0N/A
0N/A throw new AccessException(
0N/A "Registry." + op + " disallowed; origin " +
0N/A clientHost + " is non-local host");
0N/A }
0N/A }
0N/A } catch (ServerNotActiveException ex) {
0N/A /*
0N/A * Local call from this VM: allow access.
0N/A */
0N/A } catch (java.net.UnknownHostException ex) {
0N/A throw new AccessException("Registry." + op +
0N/A " disallowed; origin is unknown host");
0N/A }
0N/A }
0N/A
0N/A public static ObjID getID() {
0N/A return id;
0N/A }
0N/A
0N/A /**
0N/A * Retrieves text resources from the locale-specific properties file.
0N/A */
0N/A private static String getTextResource(String key) {
0N/A if (resources == null) {
0N/A try {
0N/A resources = ResourceBundle.getBundle(
0N/A "sun.rmi.registry.resources.rmiregistry");
0N/A } catch (MissingResourceException mre) {
0N/A }
0N/A if (resources == null) {
0N/A // throwing an Error is a bit extreme, methinks
0N/A return ("[missing resource file: " + key + "]");
0N/A }
0N/A }
0N/A
0N/A String val = null;
0N/A try {
0N/A val = resources.getString(key);
0N/A } catch (MissingResourceException mre) {
0N/A }
0N/A
0N/A if (val == null) {
0N/A return ("[missing resource: " + key + "]");
0N/A } else {
0N/A return (val);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Main program to start a registry. <br>
0N/A * The port number can be specified on the command line.
0N/A */
0N/A public static void main(String args[])
0N/A {
0N/A // Create and install the security manager if one is not installed
0N/A // already.
0N/A if (System.getSecurityManager() == null) {
0N/A System.setSecurityManager(new RMISecurityManager());
0N/A }
0N/A
0N/A try {
0N/A /*
0N/A * Fix bugid 4147561: When JDK tools are executed, the value of
0N/A * the CLASSPATH environment variable for the shell in which they
0N/A * were invoked is no longer incorporated into the application
0N/A * class path; CLASSPATH's only effect is to be the value of the
0N/A * system property "env.class.path". To preserve the previous
0N/A * (JDK1.1 and JDK1.2beta3) behavior of this tool, however, its
0N/A * CLASSPATH should still be considered when resolving classes
0N/A * being unmarshalled. To effect this old behavior, a class
0N/A * loader that loads from the file path specified in the
0N/A * "env.class.path" property is created and set to be the context
0N/A * class loader before the remote object is exported.
0N/A */
0N/A String envcp = System.getProperty("env.class.path");
0N/A if (envcp == null) {
0N/A envcp = "."; // preserve old default behavior
0N/A }
0N/A URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp);
0N/A ClassLoader cl = new URLClassLoader(urls);
0N/A
0N/A /*
0N/A * Fix bugid 4242317: Classes defined by this class loader should
0N/A * be annotated with the value of the "java.rmi.server.codebase"
0N/A * property, not the "file:" URLs for the CLASSPATH elements.
0N/A */
0N/A sun.rmi.server.LoaderHandler.registerCodebaseLoader(cl);
0N/A
0N/A Thread.currentThread().setContextClassLoader(cl);
0N/A
4455N/A final int regPort = (args.length >= 1) ? Integer.parseInt(args[0])
4455N/A : Registry.REGISTRY_PORT;
4455N/A try {
4455N/A registry = AccessController.doPrivileged(
4455N/A new PrivilegedExceptionAction<RegistryImpl>() {
4455N/A public RegistryImpl run() throws RemoteException {
4455N/A return new RegistryImpl(regPort);
4455N/A }
4483N/A }, getAccessControlContext());
4455N/A } catch (PrivilegedActionException ex) {
4455N/A throw (RemoteException) ex.getException();
0N/A }
4455N/A
0N/A // prevent registry from exiting
0N/A while (true) {
0N/A try {
0N/A Thread.sleep(Long.MAX_VALUE);
0N/A } catch (InterruptedException e) {
0N/A }
0N/A }
0N/A } catch (NumberFormatException e) {
0N/A System.err.println(MessageFormat.format(
0N/A getTextResource("rmiregistry.port.badnumber"),
0N/A args[0] ));
0N/A System.err.println(MessageFormat.format(
0N/A getTextResource("rmiregistry.usage"),
0N/A "rmiregistry" ));
0N/A } catch (Exception e) {
0N/A e.printStackTrace();
0N/A }
0N/A System.exit(1);
0N/A }
4455N/A
4455N/A /**
4483N/A * Generates an AccessControlContext with minimal permissions.
4455N/A * The approach used here is taken from the similar method
4455N/A * getAccessControlContext() in the sun.applet.AppletPanel class.
4455N/A */
4483N/A private static AccessControlContext getAccessControlContext() {
4455N/A // begin with permissions granted to all code in current policy
4455N/A PermissionCollection perms = AccessController.doPrivileged(
4455N/A new java.security.PrivilegedAction<PermissionCollection>() {
4455N/A public PermissionCollection run() {
4455N/A CodeSource codesource = new CodeSource(null,
4455N/A (java.security.cert.Certificate[]) null);
4455N/A Policy p = java.security.Policy.getPolicy();
4455N/A if (p != null) {
4455N/A return p.getPermissions(codesource);
4455N/A } else {
4455N/A return new Permissions();
4455N/A }
4455N/A }
4455N/A });
4455N/A
4455N/A /*
4455N/A * Anyone can connect to the registry and the registry can connect
4455N/A * to and possibly download stubs from anywhere. Downloaded stubs and
4455N/A * related classes themselves are more tightly limited by RMI.
4455N/A */
4455N/A perms.add(new SocketPermission("*", "connect,accept"));
4455N/A
5400N/A perms.add(new RuntimePermission("accessClassInPackage.sun.jvmstat.*"));
5400N/A perms.add(new RuntimePermission("accessClassInPackage.sun.jvm.hotspot.*"));
4459N/A
4483N/A perms.add(new FilePermission("<<ALL FILES>>", "read"));
4455N/A
4455N/A /*
4455N/A * Create an AccessControlContext that consists of a single
4455N/A * protection domain with only the permissions calculated above.
4455N/A */
4455N/A ProtectionDomain pd = new ProtectionDomain(
4483N/A new CodeSource(null,
4483N/A (java.security.cert.Certificate[]) null), perms);
4455N/A return new AccessControlContext(new ProtectionDomain[] { pd });
4455N/A }
0N/A}