History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/management/jmxremote/ConnectorBootstrap.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/management/jmxremote/ConnectorBootstrap.java+785−0
@@ -0,0 +1,785 @@
1+/*
2+ * Copyright (c) 2003, 2008, 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.management.jmxremote;
27+
28+import java.io.BufferedInputStream;
29+import java.io.File;
30+import java.io.FileInputStream;
31+import java.io.InputStream;
32+import java.io.IOException;
33+
34+import java.net.InetAddress;
35+import java.net.MalformedURLException;
36+import java.net.UnknownHostException;
37+
38+import java.rmi.NoSuchObjectException;
39+import java.rmi.Remote;
40+import java.rmi.RemoteException;
41+import java.rmi.registry.Registry;
42+import java.rmi.server.RemoteObject;
43+import java.rmi.server.RMIClientSocketFactory;
44+import java.rmi.server.RMIServerSocketFactory;
45+import java.rmi.server.UnicastRemoteObject;
46+
47+import java.security.KeyStore;
48+import java.security.Principal;
49+
50+import java.util.HashMap;
51+import java.util.HashSet;
52+import java.util.Iterator;
53+import java.util.Map;
54+import java.util.Properties;
55+import java.util.Set;
56+import java.util.StringTokenizer;
57+
58+import java.lang.management.ManagementFactory;
59+
60+import javax.net.ssl.*;
61+
62+import javax.management.MBeanServer;
63+import javax.management.remote.JMXAuthenticator;
64+import javax.management.remote.JMXConnectorServer;
65+import javax.management.remote.JMXConnectorServerFactory;
66+import javax.management.remote.JMXServiceURL;
67+import javax.management.remote.rmi.RMIConnectorServer;
68+
69+import javax.rmi.ssl.SslRMIClientSocketFactory;
70+import javax.rmi.ssl.SslRMIServerSocketFactory;
71+
72+import javax.security.auth.Subject;
73+
74+import sun.rmi.server.UnicastRef;
75+import sun.rmi.server.UnicastServerRef;
76+import sun.rmi.server.UnicastServerRef2;
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 com.sun.jmx.remote.util.ClassLogger;
84+
85+import com.sun.jmx.remote.internal.RMIExporter;
86+import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
87+
88+/**
89+ * This class initializes and starts the RMIConnectorServer for JSR 163
90+ * JMX Monitoring.
91+ **/
92+public final class ConnectorBootstrap {
93+
94+ /**
95+ * Default values for JMX configuration properties.
96+ **/
97+ public static interface DefaultValues {
98+
99+ public static final String PORT = "0";
100+ public static final String CONFIG_FILE_NAME = "management.properties";
101+ public static final String USE_SSL = "true";
102+ public static final String USE_LOCAL_ONLY = "true";
103+ public static final String USE_REGISTRY_SSL = "false";
104+ public static final String USE_AUTHENTICATION = "true";
105+ public static final String PASSWORD_FILE_NAME = "jmxremote.password";
106+ public static final String ACCESS_FILE_NAME = "jmxremote.access";
107+ public static final String SSL_NEED_CLIENT_AUTH = "false";
108+ }
109+
110+ /**
111+ * Names of JMX configuration properties.
112+ **/
113+ public static interface PropertyNames {
114+
115+ public static final String PORT =
116+ "com.sun.management.jmxremote.port";
117+ public static final String CONFIG_FILE_NAME =
118+ "com.sun.management.config.file";
119+ public static final String USE_LOCAL_ONLY =
120+ "com.sun.management.jmxremote.local.only";
121+ public static final String USE_SSL =
122+ "com.sun.management.jmxremote.ssl";
123+ public static final String USE_REGISTRY_SSL =
124+ "com.sun.management.jmxremote.registry.ssl";
125+ public static final String USE_AUTHENTICATION =
126+ "com.sun.management.jmxremote.authenticate";
127+ public static final String PASSWORD_FILE_NAME =
128+ "com.sun.management.jmxremote.password.file";
129+ public static final String ACCESS_FILE_NAME =
130+ "com.sun.management.jmxremote.access.file";
131+ public static final String LOGIN_CONFIG_NAME =
132+ "com.sun.management.jmxremote.login.config";
133+ public static final String SSL_ENABLED_CIPHER_SUITES =
134+ "com.sun.management.jmxremote.ssl.enabled.cipher.suites";
135+ public static final String SSL_ENABLED_PROTOCOLS =
136+ "com.sun.management.jmxremote.ssl.enabled.protocols";
137+ public static final String SSL_NEED_CLIENT_AUTH =
138+ "com.sun.management.jmxremote.ssl.need.client.auth";
139+ public static final String SSL_CONFIG_FILE_NAME =
140+ "com.sun.management.jmxremote.ssl.config.file";
141+ }
142+
143+ /**
144+ * JMXConnectorServer associated data.
145+ */
146+ private static class JMXConnectorServerData {
147+
148+ public JMXConnectorServerData(
149+ JMXConnectorServer jmxConnectorServer,
150+ JMXServiceURL jmxRemoteURL) {
151+ this.jmxConnectorServer = jmxConnectorServer;
152+ this.jmxRemoteURL = jmxRemoteURL;
153+ }
154+ JMXConnectorServer jmxConnectorServer;
155+ JMXServiceURL jmxRemoteURL;
156+ }
157+
158+ /**
159+ * <p>Prevents our RMI server objects from keeping the JVM alive.</p>
160+ *
161+ * <p>We use a private interface in Sun's JMX Remote API implementation
162+ * that allows us to specify how to export RMI objects. We do so using
163+ * UnicastServerRef, a class in Sun's RMI implementation. This is all
164+ * non-portable, of course, so this is only valid because we are inside
165+ * Sun's JRE.</p>
166+ *
167+ * <p>Objects are exported using {@link
168+ * UnicastServerRef#exportObject(Remote, Object, boolean)}. The
169+ * boolean parameter is called <code>permanent</code> and means
170+ * both that the object is not eligible for Distributed Garbage
171+ * Collection, and that its continued existence will not prevent
172+ * the JVM from exiting. It is the latter semantics we want (we
173+ * already have the former because of the way the JMX Remote API
174+ * works). Hence the somewhat misleading name of this class.</p>
175+ */
176+ private static class PermanentExporter implements RMIExporter {
177+
178+ public Remote exportObject(Remote obj,
179+ int port,
180+ RMIClientSocketFactory csf,
181+ RMIServerSocketFactory ssf)
182+ throws RemoteException {
183+
184+ synchronized (this) {
185+ if (firstExported == null) {
186+ firstExported = obj;
187+ }
188+ }
189+
190+ final UnicastServerRef ref;
191+ if (csf == null && ssf == null) {
192+ ref = new UnicastServerRef(port);
193+ } else {
194+ ref = new UnicastServerRef2(port, csf, ssf);
195+ }
196+ return ref.exportObject(obj, null, true);
197+ }
198+
199+ // Nothing special to be done for this case
200+ public boolean unexportObject(Remote obj, boolean force)
201+ throws NoSuchObjectException {
202+ return UnicastRemoteObject.unexportObject(obj, force);
203+ }
204+ Remote firstExported;
205+ }
206+
207+ /**
208+ * This JMXAuthenticator wraps the JMXPluggableAuthenticator and verifies
209+ * that at least one of the principal names contained in the authenticated
210+ * Subject is present in the access file.
211+ */
212+ private static class AccessFileCheckerAuthenticator
213+ implements JMXAuthenticator {
214+
215+ public AccessFileCheckerAuthenticator(Map<String, Object> env) throws IOException {
216+ environment = env;
217+ accessFile = (String) env.get("jmx.remote.x.access.file");
218+ properties = propertiesFromFile(accessFile);
219+ }
220+
221+ public Subject authenticate(Object credentials) {
222+ final JMXAuthenticator authenticator =
223+ new JMXPluggableAuthenticator(environment);
224+ final Subject subject = authenticator.authenticate(credentials);
225+ checkAccessFileEntries(subject);
226+ return subject;
227+ }
228+
229+ private void checkAccessFileEntries(Subject subject) {
230+ if (subject == null) {
231+ throw new SecurityException(
232+ "Access denied! No matching entries found in " +
233+ "the access file [" + accessFile + "] as the " +
234+ "authenticated Subject is null");
235+ }
236+ final Set principals = subject.getPrincipals();
237+ for (Iterator i = principals.iterator(); i.hasNext();) {
238+ final Principal p = (Principal) i.next();
239+ if (properties.containsKey(p.getName())) {
240+ return;
241+ }
242+ }
243+ final Set<String> principalsStr = new HashSet<String>();
244+ for (Iterator i = principals.iterator(); i.hasNext();) {
245+ final Principal p = (Principal) i.next();
246+ principalsStr.add(p.getName());
247+ }
248+ throw new SecurityException(
249+ "Access denied! No entries found in the access file [" +
250+ accessFile + "] for any of the authenticated identities " +
251+ principalsStr);
252+ }
253+
254+ private static Properties propertiesFromFile(String fname)
255+ throws IOException {
256+ Properties p = new Properties();
257+ if (fname == null) {
258+ return p;
259+ }
260+ FileInputStream fin = new FileInputStream(fname);
261+ p.load(fin);
262+ fin.close();
263+ return p;
264+ }
265+ private final Map<String, Object> environment;
266+ private final Properties properties;
267+ private final String accessFile;
268+ }
269+
270+ /**
271+ * Initializes and starts the JMX Connector Server.
272+ * If the com.sun.management.jmxremote.port property is not defined,
273+ * simply return. Otherwise, attempts to load the config file, and
274+ * then calls {@link #initialize(java.lang.String, java.util.Properties)}.
275+ *
276+ **/
277+ public static synchronized JMXConnectorServer initialize() {
278+
279+ // Load a new management properties
280+ final Properties props = Agent.loadManagementProperties();
281+ if (props == null) {
282+ return null;
283+ }
284+
285+ final String portStr = props.getProperty(PropertyNames.PORT);
286+
287+
288+ // System.out.println("initializing: {port=" + portStr + ",
289+ // properties="+props+"}");
290+ return initialize(portStr, props);
291+ }
292+
293+ /**
294+ * Initializes and starts a JMX Connector Server for remote
295+ * monitoring and management.
296+ **/
297+ public static synchronized JMXConnectorServer initialize(String portStr, Properties props) {
298+
299+ // Get port number
300+ final int port;
301+ try {
302+ port = Integer.parseInt(portStr);
303+ } catch (NumberFormatException x) {
304+ throw new AgentConfigurationError(INVALID_JMXREMOTE_PORT, x, portStr);
305+ }
306+ if (port < 0) {
307+ throw new AgentConfigurationError(INVALID_JMXREMOTE_PORT, portStr);
308+ }
309+
310+ // Do we use authentication?
311+ final String useAuthenticationStr =
312+ props.getProperty(PropertyNames.USE_AUTHENTICATION,
313+ DefaultValues.USE_AUTHENTICATION);
314+ final boolean useAuthentication =
315+ Boolean.valueOf(useAuthenticationStr).booleanValue();
316+
317+ // Do we use SSL?
318+ final String useSslStr =
319+ props.getProperty(PropertyNames.USE_SSL,
320+ DefaultValues.USE_SSL);
321+ final boolean useSsl =
322+ Boolean.valueOf(useSslStr).booleanValue();
323+
324+ // Do we use RMI Registry SSL?
325+ final String useRegistrySslStr =
326+ props.getProperty(PropertyNames.USE_REGISTRY_SSL,
327+ DefaultValues.USE_REGISTRY_SSL);
328+ final boolean useRegistrySsl =
329+ Boolean.valueOf(useRegistrySslStr).booleanValue();
330+
331+ final String enabledCipherSuites =
332+ props.getProperty(PropertyNames.SSL_ENABLED_CIPHER_SUITES);
333+ String enabledCipherSuitesList[] = null;
334+ if (enabledCipherSuites != null) {
335+ StringTokenizer st = new StringTokenizer(enabledCipherSuites, ",");
336+ int tokens = st.countTokens();
337+ enabledCipherSuitesList = new String[tokens];
338+ for (int i = 0; i < tokens; i++) {
339+ enabledCipherSuitesList[i] = st.nextToken();
340+ }
341+ }
342+
343+ final String enabledProtocols =
344+ props.getProperty(PropertyNames.SSL_ENABLED_PROTOCOLS);
345+ String enabledProtocolsList[] = null;
346+ if (enabledProtocols != null) {
347+ StringTokenizer st = new StringTokenizer(enabledProtocols, ",");
348+ int tokens = st.countTokens();
349+ enabledProtocolsList = new String[tokens];
350+ for (int i = 0; i < tokens; i++) {
351+ enabledProtocolsList[i] = st.nextToken();
352+ }
353+ }
354+
355+ final String sslNeedClientAuthStr =
356+ props.getProperty(PropertyNames.SSL_NEED_CLIENT_AUTH,
357+ DefaultValues.SSL_NEED_CLIENT_AUTH);
358+ final boolean sslNeedClientAuth =
359+ Boolean.valueOf(sslNeedClientAuthStr).booleanValue();
360+
361+ // Read SSL config file name
362+ final String sslConfigFileName =
363+ props.getProperty(PropertyNames.SSL_CONFIG_FILE_NAME);
364+
365+ String loginConfigName = null;
366+ String passwordFileName = null;
367+ String accessFileName = null;
368+
369+ // Initialize settings when authentication is active
370+ if (useAuthentication) {
371+
372+ // Get non-default login configuration
373+ loginConfigName =
374+ props.getProperty(PropertyNames.LOGIN_CONFIG_NAME);
375+
376+ if (loginConfigName == null) {
377+ // Get password file
378+ passwordFileName =
379+ props.getProperty(PropertyNames.PASSWORD_FILE_NAME,
380+ getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME));
381+ checkPasswordFile(passwordFileName);
382+ }
383+
384+ // Get access file
385+ accessFileName = props.getProperty(PropertyNames.ACCESS_FILE_NAME,
386+ getDefaultFileName(DefaultValues.ACCESS_FILE_NAME));
387+ checkAccessFile(accessFileName);
388+ }
389+
390+ if (log.debugOn()) {
391+ log.debug("initialize",
392+ Agent.getText("jmxremote.ConnectorBootstrap.initialize") +
393+ "\n\t" + PropertyNames.PORT + "=" + port +
394+ "\n\t" + PropertyNames.USE_SSL + "=" + useSsl +
395+ "\n\t" + PropertyNames.USE_REGISTRY_SSL + "=" + useRegistrySsl +
396+ "\n\t" + PropertyNames.SSL_CONFIG_FILE_NAME + "=" + sslConfigFileName +
397+ "\n\t" + PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" +
398+ enabledCipherSuites +
399+ "\n\t" + PropertyNames.SSL_ENABLED_PROTOCOLS + "=" +
400+ enabledProtocols +
401+ "\n\t" + PropertyNames.SSL_NEED_CLIENT_AUTH + "=" +
402+ sslNeedClientAuth +
403+ "\n\t" + PropertyNames.USE_AUTHENTICATION + "=" +
404+ useAuthentication +
405+ (useAuthentication ? (loginConfigName == null ? ("\n\t" + PropertyNames.PASSWORD_FILE_NAME + "=" +
406+ passwordFileName) : ("\n\t" + PropertyNames.LOGIN_CONFIG_NAME + "=" +
407+ loginConfigName)) : "\n\t" +
408+ Agent.getText("jmxremote.ConnectorBootstrap.initialize.noAuthentication")) +
409+ (useAuthentication ? ("\n\t" + PropertyNames.ACCESS_FILE_NAME + "=" +
410+ accessFileName) : "") +
411+ "");
412+ }
413+
414+ final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
415+ JMXConnectorServer cs = null;
416+ JMXServiceURL url = null;
417+ try {
418+ final JMXConnectorServerData data = exportMBeanServer(
419+ mbs, port, useSsl, useRegistrySsl,
420+ sslConfigFileName, enabledCipherSuitesList,
421+ enabledProtocolsList, sslNeedClientAuth,
422+ useAuthentication, loginConfigName,
423+ passwordFileName, accessFileName);
424+ cs = data.jmxConnectorServer;
425+ url = data.jmxRemoteURL;
426+ log.config("initialize",
427+ Agent.getText("jmxremote.ConnectorBootstrap.initialize.ready",
428+ url.toString()));
429+ } catch (Exception e) {
430+ throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
431+ }
432+ try {
433+ // Export remote connector address and associated configuration
434+ // properties to the instrumentation buffer.
435+ Map<String, String> properties = new HashMap<String, String>();
436+ properties.put("remoteAddress", url.toString());
437+ properties.put("authenticate", useAuthenticationStr);
438+ properties.put("ssl", useSslStr);
439+ properties.put("sslRegistry", useRegistrySslStr);
440+ properties.put("sslNeedClientAuth", sslNeedClientAuthStr);
441+ ConnectorAddressLink.exportRemote(properties);
442+ } catch (Exception e) {
443+ // Remote connector server started but unable to export remote
444+ // connector address and associated configuration properties to
445+ // the instrumentation buffer - non-fatal error.
446+ log.debug("initialize", e);
447+ }
448+ return cs;
449+ }
450+
451+ /*
452+ * Creates and starts a RMI Connector Server for "local" monitoring
453+ * and management.
454+ */
455+ public static JMXConnectorServer startLocalConnectorServer() {
456+ // Ensure cryptographically strong random number generater used
457+ // to choose the object number - see java.rmi.server.ObjID
458+ System.setProperty("java.rmi.server.randomIDs", "true");
459+
460+ // This RMI server should not keep the VM alive
461+ Map<String, Object> env = new HashMap<String, Object>();
462+ env.put(RMIExporter.EXPORTER_ATTRIBUTE, new PermanentExporter());
463+
464+ // The local connector server need only be available via the
465+ // loopback connection.
466+ String localhost = "localhost";
467+ InetAddress lh = null;
468+ try {
469+ lh = InetAddress.getByName(localhost);
470+ localhost = lh.getHostAddress();
471+ } catch (UnknownHostException x) {
472+ }
473+
474+ // localhost unknown or (somehow) didn't resolve to
475+ // a loopback address.
476+ if (lh == null || !lh.isLoopbackAddress()) {
477+ localhost = "127.0.0.1";
478+ }
479+
480+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
481+ try {
482+ JMXServiceURL url = new JMXServiceURL("rmi", localhost, 0);
483+ // Do we accept connections from local interfaces only?
484+ Properties props = Agent.getManagementProperties();
485+ if (props == null) {
486+ props = new Properties();
487+ }
488+ String useLocalOnlyStr = props.getProperty(
489+ PropertyNames.USE_LOCAL_ONLY, DefaultValues.USE_LOCAL_ONLY);
490+ boolean useLocalOnly = Boolean.valueOf(useLocalOnlyStr).booleanValue();
491+ if (useLocalOnly) {
492+ env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
493+ new LocalRMIServerSocketFactory());
494+ }
495+ JMXConnectorServer server =
496+ JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
497+ server.start();
498+ return server;
499+ } catch (Exception e) {
500+ throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
501+ }
502+ }
503+
504+ private static void checkPasswordFile(String passwordFileName) {
505+ if (passwordFileName == null || passwordFileName.length() == 0) {
506+ throw new AgentConfigurationError(PASSWORD_FILE_NOT_SET);
507+ }
508+ File file = new File(passwordFileName);
509+ if (!file.exists()) {
510+ throw new AgentConfigurationError(PASSWORD_FILE_NOT_FOUND, passwordFileName);
511+ }
512+
513+ if (!file.canRead()) {
514+ throw new AgentConfigurationError(PASSWORD_FILE_NOT_READABLE, passwordFileName);
515+ }
516+
517+ FileSystem fs = FileSystem.open();
518+ try {
519+ if (fs.supportsFileSecurity(file)) {
520+ if (!fs.isAccessUserOnly(file)) {
521+ final String msg = Agent.getText("jmxremote.ConnectorBootstrap.initialize.password.readonly",
522+ passwordFileName);
523+ log.config("initialize", msg);
524+ throw new AgentConfigurationError(PASSWORD_FILE_ACCESS_NOT_RESTRICTED,
525+ passwordFileName);
526+ }
527+ }
528+ } catch (IOException e) {
529+ throw new AgentConfigurationError(PASSWORD_FILE_READ_FAILED,
530+ e, passwordFileName);
531+ }
532+ }
533+
534+ private static void checkAccessFile(String accessFileName) {
535+ if (accessFileName == null || accessFileName.length() == 0) {
536+ throw new AgentConfigurationError(ACCESS_FILE_NOT_SET);
537+ }
538+ File file = new File(accessFileName);
539+ if (!file.exists()) {
540+ throw new AgentConfigurationError(ACCESS_FILE_NOT_FOUND, accessFileName);
541+ }
542+
543+ if (!file.canRead()) {
544+ throw new AgentConfigurationError(ACCESS_FILE_NOT_READABLE, accessFileName);
545+ }
546+ }
547+
548+ private static void checkRestrictedFile(String restrictedFileName) {
549+ if (restrictedFileName == null || restrictedFileName.length() == 0) {
550+ throw new AgentConfigurationError(FILE_NOT_SET);
551+ }
552+ File file = new File(restrictedFileName);
553+ if (!file.exists()) {
554+ throw new AgentConfigurationError(FILE_NOT_FOUND, restrictedFileName);
555+ }
556+ if (!file.canRead()) {
557+ throw new AgentConfigurationError(FILE_NOT_READABLE, restrictedFileName);
558+ }
559+ FileSystem fs = FileSystem.open();
560+ try {
561+ if (fs.supportsFileSecurity(file)) {
562+ if (!fs.isAccessUserOnly(file)) {
563+ final String msg = Agent.getText(
564+ "jmxremote.ConnectorBootstrap.initialize.file.readonly",
565+ restrictedFileName);
566+ log.config("initialize", msg);
567+ throw new AgentConfigurationError(
568+ FILE_ACCESS_NOT_RESTRICTED, restrictedFileName);
569+ }
570+ }
571+ } catch (IOException e) {
572+ throw new AgentConfigurationError(
573+ FILE_READ_FAILED, e, restrictedFileName);
574+ }
575+ }
576+
577+ /**
578+ * Compute the full path name for a default file.
579+ * @param basename basename (with extension) of the default file.
580+ * @return ${JRE}/lib/management/${basename}
581+ **/
582+ private static String getDefaultFileName(String basename) {
583+ final String fileSeparator = File.separator;
584+ return System.getProperty("java.home") + fileSeparator + "lib" +
585+ fileSeparator + "management" + fileSeparator +
586+ basename;
587+ }
588+
589+ private static SslRMIServerSocketFactory createSslRMIServerSocketFactory(
590+ String sslConfigFileName,
591+ String[] enabledCipherSuites,
592+ String[] enabledProtocols,
593+ boolean sslNeedClientAuth) {
594+ if (sslConfigFileName == null) {
595+ return new SslRMIServerSocketFactory(
596+ enabledCipherSuites,
597+ enabledProtocols,
598+ sslNeedClientAuth);
599+ } else {
600+ checkRestrictedFile(sslConfigFileName);
601+ try {
602+ // Load the SSL keystore properties from the config file
603+ Properties p = new Properties();
604+ InputStream in = new FileInputStream(sslConfigFileName);
605+ try {
606+ BufferedInputStream bin = new BufferedInputStream(in);
607+ p.load(bin);
608+ } finally {
609+ in.close();
610+ }
611+ String keyStore =
612+ p.getProperty("javax.net.ssl.keyStore");
613+ String keyStorePassword =
614+ p.getProperty("javax.net.ssl.keyStorePassword", "");
615+ String trustStore =
616+ p.getProperty("javax.net.ssl.trustStore");
617+ String trustStorePassword =
618+ p.getProperty("javax.net.ssl.trustStorePassword", "");
619+
620+ char[] keyStorePasswd = null;
621+ if (keyStorePassword.length() != 0) {
622+ keyStorePasswd = keyStorePassword.toCharArray();
623+ }
624+
625+ char[] trustStorePasswd = null;
626+ if (trustStorePassword.length() != 0) {
627+ trustStorePasswd = trustStorePassword.toCharArray();
628+ }
629+
630+ KeyStore ks = null;
631+ if (keyStore != null) {
632+ ks = KeyStore.getInstance(KeyStore.getDefaultType());
633+ FileInputStream ksfis = new FileInputStream(keyStore);
634+ try {
635+ ks.load(ksfis, keyStorePasswd);
636+ } finally {
637+ ksfis.close();
638+ }
639+ }
640+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(
641+ KeyManagerFactory.getDefaultAlgorithm());
642+ kmf.init(ks, keyStorePasswd);
643+
644+ KeyStore ts = null;
645+ if (trustStore != null) {
646+ ts = KeyStore.getInstance(KeyStore.getDefaultType());
647+ FileInputStream tsfis = new FileInputStream(trustStore);
648+ try {
649+ ts.load(tsfis, trustStorePasswd);
650+ } finally {
651+ tsfis.close();
652+ }
653+ }
654+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(
655+ TrustManagerFactory.getDefaultAlgorithm());
656+ tmf.init((KeyStore) ts);
657+
658+ SSLContext ctx = SSLContext.getInstance("SSL");
659+ ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
660+
661+ return new SslRMIServerSocketFactory(
662+ ctx,
663+ enabledCipherSuites,
664+ enabledProtocols,
665+ sslNeedClientAuth);
666+ } catch (Exception e) {
667+ throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
668+ }
669+ }
670+ }
671+
672+ private static JMXConnectorServerData exportMBeanServer(
673+ MBeanServer mbs,
674+ int port,
675+ boolean useSsl,
676+ boolean useRegistrySsl,
677+ String sslConfigFileName,
678+ String[] enabledCipherSuites,
679+ String[] enabledProtocols,
680+ boolean sslNeedClientAuth,
681+ boolean useAuthentication,
682+ String loginConfigName,
683+ String passwordFileName,
684+ String accessFileName)
685+ throws IOException, MalformedURLException {
686+
687+ /* Make sure we use non-guessable RMI object IDs. Otherwise
688+ * attackers could hijack open connections by guessing their
689+ * IDs. */
690+ System.setProperty("java.rmi.server.randomIDs", "true");
691+
692+ JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
693+
694+ Map<String, Object> env = new HashMap<String, Object>();
695+
696+ PermanentExporter exporter = new PermanentExporter();
697+
698+ env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
699+
700+ if (useAuthentication) {
701+ if (loginConfigName != null) {
702+ env.put("jmx.remote.x.login.config", loginConfigName);
703+ }
704+ if (passwordFileName != null) {
705+ env.put("jmx.remote.x.password.file", passwordFileName);
706+ }
707+
708+ env.put("jmx.remote.x.access.file", accessFileName);
709+
710+ if (env.get("jmx.remote.x.password.file") != null ||
711+ env.get("jmx.remote.x.login.config") != null) {
712+ env.put(JMXConnectorServer.AUTHENTICATOR,
713+ new AccessFileCheckerAuthenticator(env));
714+ }
715+ }
716+
717+ RMIClientSocketFactory csf = null;
718+ RMIServerSocketFactory ssf = null;
719+
720+ if (useSsl || useRegistrySsl) {
721+ csf = new SslRMIClientSocketFactory();
722+ ssf = createSslRMIServerSocketFactory(
723+ sslConfigFileName, enabledCipherSuites,
724+ enabledProtocols, sslNeedClientAuth);
725+ }
726+
727+ if (useSsl) {
728+ env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
729+ csf);
730+ env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
731+ ssf);
732+ }
733+
734+ JMXConnectorServer connServer = null;
735+ try {
736+ connServer =
737+ JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
738+ connServer.start();
739+ } catch (IOException e) {
740+ if (connServer == null) {
741+ throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
742+ e, url.toString());
743+ } else {
744+ throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
745+ e, connServer.getAddress().toString());
746+ }
747+ }
748+
749+ final Registry registry;
750+ if (useRegistrySsl) {
751+ registry =
752+ new SingleEntryRegistry(port, csf, ssf,
753+ "jmxrmi", exporter.firstExported);
754+ } else {
755+ registry =
756+ new SingleEntryRegistry(port,
757+ "jmxrmi", exporter.firstExported);
758+ }
759+
760+ JMXServiceURL remoteURL = new JMXServiceURL(
761+ "service:jmx:rmi:///jndi/rmi://" + url.getHost() + ":" +
762+ ((UnicastRef) ((RemoteObject) registry).getRef()).getLiveRef().getPort() +
763+ "/jmxrmi");
764+
765+ /* Our exporter remembers the first object it was asked to
766+ export, which will be an RMIServerImpl appropriate for
767+ publication in our special registry. We could
768+ alternatively have constructed the RMIServerImpl explicitly
769+ and then constructed an RMIConnectorServer passing it as a
770+ parameter, but that's quite a bit more verbose and pulls in
771+ lots of knowledge of the RMI connector. */
772+
773+ return new JMXConnectorServerData(connServer, remoteURL);
774+ }
775+
776+ /**
777+ * This class cannot be instantiated.
778+ **/
779+ private ConnectorBootstrap() {
780+ }
781+
782+ private static final ClassLogger log =
783+ new ClassLogger(ConnectorBootstrap.class.getPackage().getName(),
784+ "ConnectorBootstrap");
785+}