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.management.jmxremote;
27
28 import java.io.BufferedInputStream;
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.lang.management.ManagementFactory;
34 import java.net.InetAddress;
35 import java.net.MalformedURLException;
36 import java.net.UnknownHostException;
37 import java.rmi.NoSuchObjectException;
38 import java.rmi.Remote;
39 import java.rmi.RemoteException;
40 import java.rmi.registry.Registry;
41 import java.rmi.server.RMIClientSocketFactory;
42 import java.rmi.server.RMIServerSocketFactory;
43 import java.rmi.server.RemoteObject;
44 import java.rmi.server.UnicastRemoteObject;
45 import java.security.KeyStore;
46 import java.security.Principal;
47 import java.util.HashMap;
48 import java.util.HashSet;
49 import java.util.Iterator;
50 import java.util.Map;
51 import java.util.Properties;
52 import java.util.Set;
53 import java.util.StringTokenizer;
54
55 import javax.management.MBeanServer;
56 import javax.management.remote.JMXAuthenticator;
57 import javax.management.remote.JMXConnectorServer;
58 import javax.management.remote.JMXConnectorServerFactory;
59 import javax.management.remote.JMXServiceURL;
60 import javax.management.remote.rmi.RMIConnectorServer;
61 import javax.net.ssl.KeyManagerFactory;
62 import javax.net.ssl.SSLContext;
63 import javax.net.ssl.TrustManagerFactory;
64 import javax.rmi.ssl.SslRMIClientSocketFactory;
65 import javax.rmi.ssl.SslRMIServerSocketFactory;
66 import javax.security.auth.Subject;
67
68 import com.sun.jmx.remote.internal.RMIExporter;
69 import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
70 import com.sun.jmx.remote.util.ClassLogger;
71
72 import sun.management.Agent;
73 import sun.management.AgentConfigurationError;
74 import static sun.management.AgentConfigurationError.*;
75 import sun.management.ConnectorAddressLink;
76 import sun.management.FileSystem;
77 import sun.rmi.server.UnicastRef;
78 import sun.rmi.server.UnicastServerRef;
79 import sun.rmi.server.UnicastServerRef2;
80
81 /**
82 * This class initializes and starts the RMIConnectorServer for JSR 163
90 public static interface DefaultValues {
91
92 public static final String PORT = "0";
93 public static final String CONFIG_FILE_NAME = "management.properties";
94 public static final String USE_SSL = "true";
95 public static final String USE_LOCAL_ONLY = "true";
96 public static final String USE_REGISTRY_SSL = "false";
97 public static final String USE_AUTHENTICATION = "true";
98 public static final String PASSWORD_FILE_NAME = "jmxremote.password";
99 public static final String ACCESS_FILE_NAME = "jmxremote.access";
100 public static final String SSL_NEED_CLIENT_AUTH = "false";
101 }
102
103 /**
104 * Names of JMX configuration properties.
105 **/
106 public static interface PropertyNames {
107
108 public static final String PORT =
109 "com.sun.management.jmxremote.port";
110 public static final String RMI_PORT =
111 "com.sun.management.jmxremote.rmi.port";
112 public static final String CONFIG_FILE_NAME =
113 "com.sun.management.config.file";
114 public static final String USE_LOCAL_ONLY =
115 "com.sun.management.jmxremote.local.only";
116 public static final String USE_SSL =
117 "com.sun.management.jmxremote.ssl";
118 public static final String USE_REGISTRY_SSL =
119 "com.sun.management.jmxremote.registry.ssl";
120 public static final String USE_AUTHENTICATION =
121 "com.sun.management.jmxremote.authenticate";
122 public static final String PASSWORD_FILE_NAME =
123 "com.sun.management.jmxremote.password.file";
124 public static final String ACCESS_FILE_NAME =
125 "com.sun.management.jmxremote.access.file";
126 public static final String LOGIN_CONFIG_NAME =
127 "com.sun.management.jmxremote.login.config";
128 public static final String SSL_ENABLED_CIPHER_SUITES =
129 "com.sun.management.jmxremote.ssl.enabled.cipher.suites";
407 if (useAuthentication) {
408
409 // Get non-default login configuration
410 loginConfigName =
411 props.getProperty(PropertyNames.LOGIN_CONFIG_NAME);
412
413 if (loginConfigName == null) {
414 // Get password file
415 passwordFileName =
416 props.getProperty(PropertyNames.PASSWORD_FILE_NAME,
417 getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME));
418 checkPasswordFile(passwordFileName);
419 }
420
421 // Get access file
422 accessFileName = props.getProperty(PropertyNames.ACCESS_FILE_NAME,
423 getDefaultFileName(DefaultValues.ACCESS_FILE_NAME));
424 checkAccessFile(accessFileName);
425 }
426
427 if (log.debugOn()) {
428 log.debug("startRemoteConnectorServer",
429 Agent.getText("jmxremote.ConnectorBootstrap.starting") +
430 "\n\t" + PropertyNames.PORT + "=" + port +
431 "\n\t" + PropertyNames.RMI_PORT + "=" + rmiPort +
432 "\n\t" + PropertyNames.USE_SSL + "=" + useSsl +
433 "\n\t" + PropertyNames.USE_REGISTRY_SSL + "=" + useRegistrySsl +
434 "\n\t" + PropertyNames.SSL_CONFIG_FILE_NAME + "=" + sslConfigFileName +
435 "\n\t" + PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" +
436 enabledCipherSuites +
437 "\n\t" + PropertyNames.SSL_ENABLED_PROTOCOLS + "=" +
438 enabledProtocols +
439 "\n\t" + PropertyNames.SSL_NEED_CLIENT_AUTH + "=" +
440 sslNeedClientAuth +
441 "\n\t" + PropertyNames.USE_AUTHENTICATION + "=" +
442 useAuthentication +
443 (useAuthentication ? (loginConfigName == null ? ("\n\t" + PropertyNames.PASSWORD_FILE_NAME + "=" +
444 passwordFileName) : ("\n\t" + PropertyNames.LOGIN_CONFIG_NAME + "=" +
445 loginConfigName)) : "\n\t" +
446 Agent.getText("jmxremote.ConnectorBootstrap.noAuthentication")) +
447 (useAuthentication ? ("\n\t" + PropertyNames.ACCESS_FILE_NAME + "=" +
448 accessFileName) : "") +
449 "");
450 }
451
452 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
453 JMXConnectorServer cs = null;
454 JMXServiceURL url = null;
455 try {
456 final JMXConnectorServerData data = exportMBeanServer(
457 mbs, port, rmiPort, useSsl, useRegistrySsl,
458 sslConfigFileName, enabledCipherSuitesList,
459 enabledProtocolsList, sslNeedClientAuth,
460 useAuthentication, loginConfigName,
461 passwordFileName, accessFileName);
462 cs = data.jmxConnectorServer;
463 url = data.jmxRemoteURL;
464 log.config("startRemoteConnectorServer",
465 Agent.getText("jmxremote.ConnectorBootstrap.ready",
466 url.toString()));
467 } catch (Exception e) {
468 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
469 }
470 try {
471 // Export remote connector address and associated configuration
472 // properties to the instrumentation buffer.
473 Map<String, String> properties = new HashMap<>();
474 properties.put("remoteAddress", url.toString());
475 properties.put("authenticate", useAuthenticationStr);
476 properties.put("ssl", useSslStr);
477 properties.put("sslRegistry", useRegistrySslStr);
478 properties.put("sslNeedClientAuth", sslNeedClientAuthStr);
479 ConnectorAddressLink.exportRemote(properties);
480 } catch (Exception e) {
481 // Remote connector server started but unable to export remote
611 FILE_READ_FAILED, e, restrictedFileName);
612 }
613 }
614
615 /**
616 * Compute the full path name for a default file.
617 * @param basename basename (with extension) of the default file.
618 * @return ${JRE}/conf/management/${basename}
619 **/
620 private static String getDefaultFileName(String basename) {
621 final String fileSeparator = File.separator;
622 return System.getProperty("java.home") + fileSeparator + "conf" +
623 fileSeparator + "management" + fileSeparator +
624 basename;
625 }
626
627 private static SslRMIServerSocketFactory createSslRMIServerSocketFactory(
628 String sslConfigFileName,
629 String[] enabledCipherSuites,
630 String[] enabledProtocols,
631 boolean sslNeedClientAuth) {
632 if (sslConfigFileName == null) {
633 return new SslRMIServerSocketFactory(
634 enabledCipherSuites,
635 enabledProtocols,
636 sslNeedClientAuth);
637 } else {
638 checkRestrictedFile(sslConfigFileName);
639 try {
640 // Load the SSL keystore properties from the config file
641 Properties p = new Properties();
642 try (InputStream in = new FileInputStream(sslConfigFileName)) {
643 BufferedInputStream bin = new BufferedInputStream(in);
644 p.load(bin);
645 }
646 String keyStore =
647 p.getProperty("javax.net.ssl.keyStore");
648 String keyStorePassword =
649 p.getProperty("javax.net.ssl.keyStorePassword", "");
650 String trustStore =
651 p.getProperty("javax.net.ssl.trustStore");
652 String trustStorePassword =
653 p.getProperty("javax.net.ssl.trustStorePassword", "");
654
655 char[] keyStorePasswd = null;
656 if (keyStorePassword.length() != 0) {
670 }
671 }
672 KeyManagerFactory kmf = KeyManagerFactory.getInstance(
673 KeyManagerFactory.getDefaultAlgorithm());
674 kmf.init(ks, keyStorePasswd);
675
676 KeyStore ts = null;
677 if (trustStore != null) {
678 ts = KeyStore.getInstance(KeyStore.getDefaultType());
679 try (FileInputStream tsfis = new FileInputStream(trustStore)) {
680 ts.load(tsfis, trustStorePasswd);
681 }
682 }
683 TrustManagerFactory tmf = TrustManagerFactory.getInstance(
684 TrustManagerFactory.getDefaultAlgorithm());
685 tmf.init(ts);
686
687 SSLContext ctx = SSLContext.getInstance("SSL");
688 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
689
690 return new SslRMIServerSocketFactory(
691 ctx,
692 enabledCipherSuites,
693 enabledProtocols,
694 sslNeedClientAuth);
695 } catch (Exception e) {
696 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
697 }
698 }
699 }
700
701 private static JMXConnectorServerData exportMBeanServer(
702 MBeanServer mbs,
703 int port,
704 int rmiPort,
705 boolean useSsl,
706 boolean useRegistrySsl,
707 String sslConfigFileName,
708 String[] enabledCipherSuites,
709 String[] enabledProtocols,
710 boolean sslNeedClientAuth,
711 boolean useAuthentication,
712 String loginConfigName,
713 String passwordFileName,
714 String accessFileName)
715 throws IOException, MalformedURLException {
716
717 /* Make sure we use non-guessable RMI object IDs. Otherwise
718 * attackers could hijack open connections by guessing their
719 * IDs. */
720 System.setProperty("java.rmi.server.randomIDs", "true");
721
722 JMXServiceURL url = new JMXServiceURL("rmi", null, rmiPort);
723
724 Map<String, Object> env = new HashMap<>();
725
726 PermanentExporter exporter = new PermanentExporter();
727
728 env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
729
730 if (useAuthentication) {
731 if (loginConfigName != null) {
732 env.put("jmx.remote.x.login.config", loginConfigName);
733 }
734 if (passwordFileName != null) {
735 env.put("jmx.remote.x.password.file", passwordFileName);
736 }
737
738 env.put("jmx.remote.x.access.file", accessFileName);
739
740 if (env.get("jmx.remote.x.password.file") != null ||
741 env.get("jmx.remote.x.login.config") != null) {
742 env.put(JMXConnectorServer.AUTHENTICATOR,
743 new AccessFileCheckerAuthenticator(env));
744 }
745 }
746
747 RMIClientSocketFactory csf = null;
748 RMIServerSocketFactory ssf = null;
749
750 if (useSsl || useRegistrySsl) {
751 csf = new SslRMIClientSocketFactory();
752 ssf = createSslRMIServerSocketFactory(
753 sslConfigFileName, enabledCipherSuites,
754 enabledProtocols, sslNeedClientAuth);
755 }
756
757 if (useSsl) {
758 env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
759 csf);
760 env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
761 ssf);
762 }
763
764 JMXConnectorServer connServer = null;
765 try {
766 connServer =
767 JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
768 connServer.start();
769 } catch (IOException e) {
770 if (connServer == null || connServer.getAddress() == null) {
771 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
772 e, url.toString());
773 } else {
774 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
775 e, connServer.getAddress().toString());
776 }
777 }
778
779 if (useRegistrySsl) {
780 registry =
781 new SingleEntryRegistry(port, csf, ssf,
782 "jmxrmi", exporter.firstExported);
783 } else {
784 registry =
785 new SingleEntryRegistry(port,
786 "jmxrmi", exporter.firstExported);
787 }
788
789
790 int registryPort =
791 ((UnicastRef) ((RemoteObject) registry).getRef()).getLiveRef().getPort();
792 String jmxUrlStr = String.format("service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi",
793 url.getHost(), registryPort);
794 JMXServiceURL remoteURL = new JMXServiceURL(jmxUrlStr);
795
796 /* Our exporter remembers the first object it was asked to
797 export, which will be an RMIServerImpl appropriate for
798 publication in our special registry. We could
799 alternatively have constructed the RMIServerImpl explicitly
800 and then constructed an RMIConnectorServer passing it as a
801 parameter, but that's quite a bit more verbose and pulls in
802 lots of knowledge of the RMI connector. */
803
804 return new JMXConnectorServerData(connServer, remoteURL);
805 }
806
807 /**
808 * This class cannot be instantiated.
809 **/
810 private ConnectorBootstrap() {
811 }
812
813 private static final ClassLogger log =
814 new ClassLogger(ConnectorBootstrap.class.getPackage().getName(),
815 "ConnectorBootstrap");
816 }
|
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.management.jmxremote;
27
28 import java.io.BufferedInputStream;
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.Serializable;
34 import java.lang.management.ManagementFactory;
35 import java.net.InetAddress;
36 import java.net.MalformedURLException;
37 import java.net.Socket;
38 import java.net.ServerSocket;
39 import java.net.UnknownHostException;
40 import java.rmi.NoSuchObjectException;
41 import java.rmi.Remote;
42 import java.rmi.RemoteException;
43 import java.rmi.registry.Registry;
44 import java.rmi.server.RMIClientSocketFactory;
45 import java.rmi.server.RMIServerSocketFactory;
46 import java.rmi.server.RMISocketFactory;
47 import java.rmi.server.RemoteObject;
48 import java.rmi.server.UnicastRemoteObject;
49 import java.security.KeyStore;
50 import java.security.Principal;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.Iterator;
54 import java.util.Map;
55 import java.util.Properties;
56 import java.util.Set;
57 import java.util.StringTokenizer;
58
59 import javax.management.MBeanServer;
60 import javax.management.remote.JMXAuthenticator;
61 import javax.management.remote.JMXConnectorServer;
62 import javax.management.remote.JMXConnectorServerFactory;
63 import javax.management.remote.JMXServiceURL;
64 import javax.management.remote.rmi.RMIConnectorServer;
65 import javax.net.ssl.KeyManagerFactory;
66 import javax.net.ssl.SSLContext;
67 import javax.net.ssl.SSLSocket;
68 import javax.net.ssl.SSLSocketFactory;
69 import javax.net.ssl.TrustManagerFactory;
70 import javax.rmi.ssl.SslRMIClientSocketFactory;
71 import javax.rmi.ssl.SslRMIServerSocketFactory;
72 import javax.security.auth.Subject;
73
74 import com.sun.jmx.remote.internal.RMIExporter;
75 import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
76 import com.sun.jmx.remote.util.ClassLogger;
77
78 import sun.management.Agent;
79 import sun.management.AgentConfigurationError;
80 import static sun.management.AgentConfigurationError.*;
81 import sun.management.ConnectorAddressLink;
82 import sun.management.FileSystem;
83 import sun.rmi.server.UnicastRef;
84 import sun.rmi.server.UnicastServerRef;
85 import sun.rmi.server.UnicastServerRef2;
86
87 /**
88 * This class initializes and starts the RMIConnectorServer for JSR 163
96 public static interface DefaultValues {
97
98 public static final String PORT = "0";
99 public static final String CONFIG_FILE_NAME = "management.properties";
100 public static final String USE_SSL = "true";
101 public static final String USE_LOCAL_ONLY = "true";
102 public static final String USE_REGISTRY_SSL = "false";
103 public static final String USE_AUTHENTICATION = "true";
104 public static final String PASSWORD_FILE_NAME = "jmxremote.password";
105 public static final String ACCESS_FILE_NAME = "jmxremote.access";
106 public static final String SSL_NEED_CLIENT_AUTH = "false";
107 }
108
109 /**
110 * Names of JMX configuration properties.
111 **/
112 public static interface PropertyNames {
113
114 public static final String PORT =
115 "com.sun.management.jmxremote.port";
116 public static final String HOST =
117 "com.sun.management.jmxremote.host";
118 public static final String RMI_PORT =
119 "com.sun.management.jmxremote.rmi.port";
120 public static final String CONFIG_FILE_NAME =
121 "com.sun.management.config.file";
122 public static final String USE_LOCAL_ONLY =
123 "com.sun.management.jmxremote.local.only";
124 public static final String USE_SSL =
125 "com.sun.management.jmxremote.ssl";
126 public static final String USE_REGISTRY_SSL =
127 "com.sun.management.jmxremote.registry.ssl";
128 public static final String USE_AUTHENTICATION =
129 "com.sun.management.jmxremote.authenticate";
130 public static final String PASSWORD_FILE_NAME =
131 "com.sun.management.jmxremote.password.file";
132 public static final String ACCESS_FILE_NAME =
133 "com.sun.management.jmxremote.access.file";
134 public static final String LOGIN_CONFIG_NAME =
135 "com.sun.management.jmxremote.login.config";
136 public static final String SSL_ENABLED_CIPHER_SUITES =
137 "com.sun.management.jmxremote.ssl.enabled.cipher.suites";
415 if (useAuthentication) {
416
417 // Get non-default login configuration
418 loginConfigName =
419 props.getProperty(PropertyNames.LOGIN_CONFIG_NAME);
420
421 if (loginConfigName == null) {
422 // Get password file
423 passwordFileName =
424 props.getProperty(PropertyNames.PASSWORD_FILE_NAME,
425 getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME));
426 checkPasswordFile(passwordFileName);
427 }
428
429 // Get access file
430 accessFileName = props.getProperty(PropertyNames.ACCESS_FILE_NAME,
431 getDefaultFileName(DefaultValues.ACCESS_FILE_NAME));
432 checkAccessFile(accessFileName);
433 }
434
435 final String bindAddress =
436 props.getProperty(PropertyNames.HOST);
437
438 if (log.debugOn()) {
439 log.debug("startRemoteConnectorServer",
440 Agent.getText("jmxremote.ConnectorBootstrap.starting") +
441 "\n\t" + PropertyNames.PORT + "=" + port +
442 "\n\t" + PropertyNames.HOST + "=" + bindAddress +
443 "\n\t" + PropertyNames.RMI_PORT + "=" + rmiPort +
444 "\n\t" + PropertyNames.USE_SSL + "=" + useSsl +
445 "\n\t" + PropertyNames.USE_REGISTRY_SSL + "=" + useRegistrySsl +
446 "\n\t" + PropertyNames.SSL_CONFIG_FILE_NAME + "=" + sslConfigFileName +
447 "\n\t" + PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" +
448 enabledCipherSuites +
449 "\n\t" + PropertyNames.SSL_ENABLED_PROTOCOLS + "=" +
450 enabledProtocols +
451 "\n\t" + PropertyNames.SSL_NEED_CLIENT_AUTH + "=" +
452 sslNeedClientAuth +
453 "\n\t" + PropertyNames.USE_AUTHENTICATION + "=" +
454 useAuthentication +
455 (useAuthentication ? (loginConfigName == null ? ("\n\t" + PropertyNames.PASSWORD_FILE_NAME + "=" +
456 passwordFileName) : ("\n\t" + PropertyNames.LOGIN_CONFIG_NAME + "=" +
457 loginConfigName)) : "\n\t" +
458 Agent.getText("jmxremote.ConnectorBootstrap.noAuthentication")) +
459 (useAuthentication ? ("\n\t" + PropertyNames.ACCESS_FILE_NAME + "=" +
460 accessFileName) : "") +
461 "");
462 }
463
464 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
465 JMXConnectorServer cs = null;
466 JMXServiceURL url = null;
467 try {
468 final JMXConnectorServerData data = exportMBeanServer(
469 mbs, port, rmiPort, useSsl, useRegistrySsl,
470 sslConfigFileName, enabledCipherSuitesList,
471 enabledProtocolsList, sslNeedClientAuth,
472 useAuthentication, loginConfigName,
473 passwordFileName, accessFileName, bindAddress);
474 cs = data.jmxConnectorServer;
475 url = data.jmxRemoteURL;
476 log.config("startRemoteConnectorServer",
477 Agent.getText("jmxremote.ConnectorBootstrap.ready",
478 url.toString()));
479 } catch (Exception e) {
480 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
481 }
482 try {
483 // Export remote connector address and associated configuration
484 // properties to the instrumentation buffer.
485 Map<String, String> properties = new HashMap<>();
486 properties.put("remoteAddress", url.toString());
487 properties.put("authenticate", useAuthenticationStr);
488 properties.put("ssl", useSslStr);
489 properties.put("sslRegistry", useRegistrySslStr);
490 properties.put("sslNeedClientAuth", sslNeedClientAuthStr);
491 ConnectorAddressLink.exportRemote(properties);
492 } catch (Exception e) {
493 // Remote connector server started but unable to export remote
623 FILE_READ_FAILED, e, restrictedFileName);
624 }
625 }
626
627 /**
628 * Compute the full path name for a default file.
629 * @param basename basename (with extension) of the default file.
630 * @return ${JRE}/conf/management/${basename}
631 **/
632 private static String getDefaultFileName(String basename) {
633 final String fileSeparator = File.separator;
634 return System.getProperty("java.home") + fileSeparator + "conf" +
635 fileSeparator + "management" + fileSeparator +
636 basename;
637 }
638
639 private static SslRMIServerSocketFactory createSslRMIServerSocketFactory(
640 String sslConfigFileName,
641 String[] enabledCipherSuites,
642 String[] enabledProtocols,
643 boolean sslNeedClientAuth,
644 String bindAddress) {
645 if (sslConfigFileName == null) {
646 return new HostAwareSslSocketFactory(
647 enabledCipherSuites,
648 enabledProtocols,
649 sslNeedClientAuth, bindAddress);
650 } else {
651 checkRestrictedFile(sslConfigFileName);
652 try {
653 // Load the SSL keystore properties from the config file
654 Properties p = new Properties();
655 try (InputStream in = new FileInputStream(sslConfigFileName)) {
656 BufferedInputStream bin = new BufferedInputStream(in);
657 p.load(bin);
658 }
659 String keyStore =
660 p.getProperty("javax.net.ssl.keyStore");
661 String keyStorePassword =
662 p.getProperty("javax.net.ssl.keyStorePassword", "");
663 String trustStore =
664 p.getProperty("javax.net.ssl.trustStore");
665 String trustStorePassword =
666 p.getProperty("javax.net.ssl.trustStorePassword", "");
667
668 char[] keyStorePasswd = null;
669 if (keyStorePassword.length() != 0) {
683 }
684 }
685 KeyManagerFactory kmf = KeyManagerFactory.getInstance(
686 KeyManagerFactory.getDefaultAlgorithm());
687 kmf.init(ks, keyStorePasswd);
688
689 KeyStore ts = null;
690 if (trustStore != null) {
691 ts = KeyStore.getInstance(KeyStore.getDefaultType());
692 try (FileInputStream tsfis = new FileInputStream(trustStore)) {
693 ts.load(tsfis, trustStorePasswd);
694 }
695 }
696 TrustManagerFactory tmf = TrustManagerFactory.getInstance(
697 TrustManagerFactory.getDefaultAlgorithm());
698 tmf.init(ts);
699
700 SSLContext ctx = SSLContext.getInstance("SSL");
701 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
702
703 return new HostAwareSslSocketFactory(
704 ctx,
705 enabledCipherSuites,
706 enabledProtocols,
707 sslNeedClientAuth, bindAddress);
708 } catch (Exception e) {
709 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
710 }
711 }
712 }
713
714 private static JMXConnectorServerData exportMBeanServer(
715 MBeanServer mbs,
716 int port,
717 int rmiPort,
718 boolean useSsl,
719 boolean useRegistrySsl,
720 String sslConfigFileName,
721 String[] enabledCipherSuites,
722 String[] enabledProtocols,
723 boolean sslNeedClientAuth,
724 boolean useAuthentication,
725 String loginConfigName,
726 String passwordFileName,
727 String accessFileName,
728 String bindAddress)
729 throws IOException, MalformedURLException {
730
731 /* Make sure we use non-guessable RMI object IDs. Otherwise
732 * attackers could hijack open connections by guessing their
733 * IDs. */
734 System.setProperty("java.rmi.server.randomIDs", "true");
735
736 JMXServiceURL url = new JMXServiceURL("rmi", bindAddress, rmiPort);
737
738 Map<String, Object> env = new HashMap<>();
739
740 PermanentExporter exporter = new PermanentExporter();
741
742 env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
743
744 boolean useSocketFactory = bindAddress != null && !useSsl;
745
746 if (useAuthentication) {
747 if (loginConfigName != null) {
748 env.put("jmx.remote.x.login.config", loginConfigName);
749 }
750 if (passwordFileName != null) {
751 env.put("jmx.remote.x.password.file", passwordFileName);
752 }
753
754 env.put("jmx.remote.x.access.file", accessFileName);
755
756 if (env.get("jmx.remote.x.password.file") != null ||
757 env.get("jmx.remote.x.login.config") != null) {
758 env.put(JMXConnectorServer.AUTHENTICATOR,
759 new AccessFileCheckerAuthenticator(env));
760 }
761 }
762
763 RMIClientSocketFactory csf = null;
764 RMIServerSocketFactory ssf = null;
765
766 if (useSsl || useRegistrySsl) {
767 csf = new SslRMIClientSocketFactory();
768 ssf = createSslRMIServerSocketFactory(
769 sslConfigFileName, enabledCipherSuites,
770 enabledProtocols, sslNeedClientAuth, bindAddress);
771 }
772
773 if (useSsl) {
774 env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
775 csf);
776 env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
777 ssf);
778 }
779
780 if (useSocketFactory) {
781 ssf = new HostAwareSocketFactory(bindAddress);
782 env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
783 ssf);
784 }
785
786 JMXConnectorServer connServer = null;
787 try {
788 connServer =
789 JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
790 connServer.start();
791 } catch (IOException e) {
792 if (connServer == null || connServer.getAddress() == null) {
793 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
794 e, url.toString());
795 } else {
796 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
797 e, connServer.getAddress().toString());
798 }
799 }
800
801 if (useRegistrySsl) {
802 registry =
803 new SingleEntryRegistry(port, csf, ssf,
804 "jmxrmi", exporter.firstExported);
805 } else if (useSocketFactory) {
806 registry =
807 new SingleEntryRegistry(port, csf, ssf,
808 "jmxrmi", exporter.firstExported);
809 } else {
810 registry =
811 new SingleEntryRegistry(port,
812 "jmxrmi", exporter.firstExported);
813 }
814
815
816 int registryPort =
817 ((UnicastRef) ((RemoteObject) registry).getRef()).getLiveRef().getPort();
818 String jmxUrlStr = String.format("service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi",
819 url.getHost(), registryPort);
820 JMXServiceURL remoteURL = new JMXServiceURL(jmxUrlStr);
821
822 /* Our exporter remembers the first object it was asked to
823 export, which will be an RMIServerImpl appropriate for
824 publication in our special registry. We could
825 alternatively have constructed the RMIServerImpl explicitly
826 and then constructed an RMIConnectorServer passing it as a
827 parameter, but that's quite a bit more verbose and pulls in
828 lots of knowledge of the RMI connector. */
829
830 return new JMXConnectorServerData(connServer, remoteURL);
831 }
832
833 /**
834 * This class cannot be instantiated.
835 **/
836 private ConnectorBootstrap() {
837 }
838
839 private static final ClassLogger log =
840 new ClassLogger(ConnectorBootstrap.class.getPackage().getName(),
841 "ConnectorBootstrap");
842
843 private static class HostAwareSocketFactory implements RMIServerSocketFactory {
844
845 private final String bindAddress;
846
847 private HostAwareSocketFactory(String bindAddress) {
848 this.bindAddress = bindAddress;
849 }
850
851 @Override
852 public ServerSocket createServerSocket(int port) throws IOException {
853 if (bindAddress == null) {
854 return new ServerSocket(port);
855 } else {
856 try {
857 InetAddress addr = InetAddress.getByName(bindAddress);
858 return new ServerSocket(port, 0, addr);
859 } catch (UnknownHostException e) {
860 return new ServerSocket(port);
861 }
862 }
863 }
864 }
865
866 private static class HostAwareSslSocketFactory extends SslRMIServerSocketFactory {
867
868 private final String bindAddress;
869 private final String[] enabledCipherSuites;
870 private final String[] enabledProtocols;
871 private final boolean needClientAuth;
872 private final SSLContext context;
873
874 private HostAwareSslSocketFactory(String[] enabledCipherSuites,
875 String[] enabledProtocols,
876 boolean sslNeedClientAuth,
877 String bindAddress) throws IllegalArgumentException {
878 this(null, enabledCipherSuites, enabledProtocols, sslNeedClientAuth, bindAddress);
879 }
880
881 private HostAwareSslSocketFactory(SSLContext ctx,
882 String[] enabledCipherSuites,
883 String[] enabledProtocols,
884 boolean sslNeedClientAuth,
885 String bindAddress) throws IllegalArgumentException {
886 this.context = ctx;
887 this.bindAddress = bindAddress;
888 this.enabledProtocols = enabledProtocols;
889 this.enabledCipherSuites = enabledCipherSuites;
890 this.needClientAuth = sslNeedClientAuth;
891 checkValues(ctx, enabledCipherSuites, enabledProtocols);
892 }
893
894 @Override
895 public ServerSocket createServerSocket(int port) throws IOException {
896 if (bindAddress != null) {
897 try {
898 InetAddress addr = InetAddress.getByName(bindAddress);
899 return new SslServerSocket(port, 0, addr, context,
900 enabledCipherSuites, enabledProtocols, needClientAuth);
901 } catch (UnknownHostException e) {
902 return new SslServerSocket(port, context,
903 enabledCipherSuites, enabledProtocols, needClientAuth);
904 }
905 } else {
906 return new SslServerSocket(port, context,
907 enabledCipherSuites, enabledProtocols, needClientAuth);
908 }
909 }
910
911 private static void checkValues(SSLContext context,
912 String[] enabledCipherSuites,
913 String[] enabledProtocols) throws IllegalArgumentException {
914 // Force the initialization of the default at construction time,
915 // rather than delaying it to the first time createServerSocket()
916 // is called.
917 //
918 final SSLSocketFactory sslSocketFactory =
919 context == null ?
920 (SSLSocketFactory)SSLSocketFactory.getDefault() : context.getSocketFactory();
921 SSLSocket sslSocket = null;
922 if (enabledCipherSuites != null || enabledProtocols != null) {
923 try {
924 sslSocket = (SSLSocket) sslSocketFactory.createSocket();
925 } catch (Exception e) {
926 final String msg = "Unable to check if the cipher suites " +
927 "and protocols to enable are supported";
928 throw (IllegalArgumentException)
929 new IllegalArgumentException(msg).initCause(e);
930 }
931 }
932
933 // Check if all the cipher suites and protocol versions to enable
934 // are supported by the underlying SSL/TLS implementation and if
935 // true create lists from arrays.
936 //
937 if (enabledCipherSuites != null) {
938 sslSocket.setEnabledCipherSuites(enabledCipherSuites);
939 }
940 if (enabledProtocols != null) {
941 sslSocket.setEnabledProtocols(enabledProtocols);
942 }
943 }
944 }
945
946 private static class SslServerSocket extends ServerSocket {
947
948 private static SSLSocketFactory defaultSSLSocketFactory;
949 private final String[] enabledCipherSuites;
950 private final String[] enabledProtocols;
951 private final boolean needClientAuth;
952 private final SSLContext context;
953
954 private SslServerSocket(int port,
955 SSLContext ctx,
956 String[] enabledCipherSuites,
957 String[] enabledProtocols,
958 boolean needClientAuth) throws IOException {
959 super(port);
960 this.enabledProtocols = enabledProtocols;
961 this.enabledCipherSuites = enabledCipherSuites;
962 this.needClientAuth = needClientAuth;
963 this.context = ctx;
964 }
965
966 private SslServerSocket(int port,
967 int backlog,
968 InetAddress bindAddr,
969 SSLContext ctx,
970 String[] enabledCipherSuites,
971 String[] enabledProtocols,
972 boolean needClientAuth) throws IOException {
973 super(port, backlog, bindAddr);
974 this.enabledProtocols = enabledProtocols;
975 this.enabledCipherSuites = enabledCipherSuites;
976 this.needClientAuth = needClientAuth;
977 this.context = ctx;
978 }
979
980 @Override
981 public Socket accept() throws IOException {
982 final SSLSocketFactory sslSocketFactory =
983 context == null ?
984 getDefaultSSLSocketFactory() : context.getSocketFactory();
985 Socket socket = super.accept();
986 SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
987 socket, socket.getInetAddress().getHostName(),
988 socket.getPort(), true);
989 sslSocket.setUseClientMode(false);
990 if (enabledCipherSuites != null) {
991 sslSocket.setEnabledCipherSuites(enabledCipherSuites);
992 }
993 if (enabledProtocols != null) {
994 sslSocket.setEnabledProtocols(enabledProtocols);
995 }
996 sslSocket.setNeedClientAuth(needClientAuth);
997 return sslSocket;
998 }
999
1000 private static synchronized SSLSocketFactory getDefaultSSLSocketFactory() {
1001 if (defaultSSLSocketFactory == null) {
1002 defaultSSLSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
1003 return defaultSSLSocketFactory;
1004 } else {
1005 return defaultSSLSocketFactory;
1006 }
1007 }
1008
1009 }
1010 }
|