Java tutorial
/* * Adito * * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package com.adito.agent.client; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.PrintStream; import java.lang.reflect.Method; import java.net.URL; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.Locale; import java.util.Properties; import java.util.StringTokenizer; import java.util.Vector; import com.maverick.http.AuthenticationCancelledException; import com.maverick.http.AuthenticationPrompt; import com.maverick.http.ConnectMethod; import com.maverick.http.GetMethod; import com.maverick.http.HttpAuthenticator; import com.maverick.http.HttpAuthenticatorFactory; import com.maverick.http.HttpClient; import com.maverick.http.HttpConnection; import com.maverick.http.HttpException; import com.maverick.http.HttpResponse; import com.maverick.http.PasswordCredentials; import com.maverick.http.URLDecoder; import com.maverick.http.UnsupportedAuthenticationException; import com.maverick.multiplex.MultiplexedConnection; import com.maverick.multiplex.MultiplexedConnectionListener; import com.maverick.multiplex.Request; import com.maverick.multiplex.RequestHandler; import com.maverick.ssl.SSLIOException; import com.maverick.ssl.SSLTransportFactory; import com.maverick.ssl.SSLTransportImpl; import com.maverick.ssl.https.HttpsURLStreamHandlerFactory; import com.maverick.util.ByteArrayReader; import com.maverick.util.ByteArrayWriter; import com.adito.agent.client.applications.ApplicationManager; import com.adito.agent.client.networkplaces.NetworkPlaceManager; import com.adito.agent.client.tunneling.DefaultTunnel; import com.adito.agent.client.tunneling.LocalTunnelServer; import com.adito.agent.client.tunneling.TunnelInactivityMonitor; import com.adito.agent.client.tunneling.TunnelManager; import com.adito.agent.client.util.BrowserLauncher; import com.adito.agent.client.util.FileCleaner; import com.adito.agent.client.util.IOStreamConnectorListener; import com.adito.agent.client.util.TunnelConfiguration; import com.adito.agent.client.util.URI; import com.adito.agent.client.util.Utils; import com.adito.agent.client.util.URI.MalformedURIException; import com.adito.agent.client.webforwards.WebForwardManager; /** * Concrete implementation of an {@link AbstractVPNClient} that runs as * standalone applicaiton launched from the Adito web interface (via the * <i>Laumcher</i> applet. * <p> * See package description for more information. */ public class Agent implements RequestHandler, MultiplexedConnectionListener { /* * Replaced by build */ public final static String AGENT_VERSION = "999.999.999"; /** The hostname of the Adito proxy * */ protected String aditoHostname; /** The port of the Adito proxy * */ protected int aditoPort; /** Are we using a secure port? **/ protected boolean isSecure = true; /** The username for this session * */ protected String username; /** The VPN client ticket for an authenticated session * */ protected String ticket; /** The hostname of the local HTTPS proxy server * */ protected URI localProxyURL; /** The hostname of the reverse HTTPS proxy server * */ protected URI reverseProxyURL; /** We store all the available proxy information here * */ protected static Hashtable proxiesIE = new Hashtable(); /** We store all the local bypass addresses here * */ protected static Vector proxyBypassIE = new Vector(); protected static Hashtable proxiesFF = new Hashtable(); protected static Vector proxyBypassFF = new Vector(); /** HttpClient instances are cached * */ protected AgentConfiguration agentConfiguration; protected String serverVersion; protected HttpClient client; protected String defaultProxyHost; protected String defaultReverseProxyHost; protected int defaultProxyPort = 80; protected int defaultReverseProxyPort = 80; protected PasswordCredentials defaultProxyCredentials; protected String defaultProxyPreferredAuthentication; protected boolean autoDetectProxies = true; protected AuthenticationPrompt defaultProxyAuthenticationPrompt; protected AuthenticationPrompt defaultAuthenticationPrompt; protected int defaultProxyType = HttpClient.PROXY_HTTP; protected int defaultReverseProxyType = HttpClient.PROXY_HTTP; protected ApplicationManager applicationManager; protected TunnelManager tunnelManager; protected WebForwardManager webForwardManager; protected NetworkPlaceManager networkPlaceManager; boolean ticketIsPassword; // Public statics /** * Client is connected */ public final static int STATE_CONNECTED = 1; /** * Client is disconnected */ public final static int STATE_DISCONNECTED = 2; // Private instance variables private int currentState = STATE_DISCONNECTED; private TXRXMonitor txm; private AgentClientGUI gui; private Vector extensions = new Vector(); private TunnelInactivityMonitor inactivityMonitor; private KeepAliveThread keepAlive; // Statics MultiplexedConnection con = null; HttpConnection httpConnection = null; public static final String SHUTDOWN_REQUEST = "shutdown"; public static final String OPEN_URL_REQUEST = "openURL"; public static final String MESSAGE_REQUEST = "agentMessage"; public static final String UPDATE_RESOURCES_REQUEST = "updateResources"; public static final String SYNCHRONIZED_REQUEST = "synchronized"; // #ifdef DEBUG static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(Agent.class); // #endif static { HttpClient.setUserAgent("Agent"); //$NON-NLS-1$ } /** * Set the URL of the HTTPS proxy server to use for all outgoing connections * * @param localProxyURL * local proxy URL * @throws URI.MalformedURIException */ public void setLocalProxyURL(String localProxyURL) throws URI.MalformedURIException { this.localProxyURL = new URI(localProxyURL); // FIXME What about HttpsURLConnection? } /** * Set the URL of the reverse HTTPS proxy server to use for all outgoing connections * * @param reverseProxyURL * reverse proxy URL * @throws URI.MalformedURIException */ public void setReverseProxyURL(String reverseProxyURL) throws URI.MalformedURIException { this.reverseProxyURL = new URI(reverseProxyURL); // FIXME What about HttpsURLConnection? } /** * Get the application manager for this agent. * * @return application manager */ public ApplicationManager getApplicationManager() { return applicationManager; } /** * Get the tunnel manager for this agent * * @return tunnel mananger */ public TunnelManager getTunnelManager() { return tunnelManager; } /** * Get the network place manager for this agent * * @return network place manager */ public NetworkPlaceManager getNetworkPlaceManager() { return networkPlaceManager; } /** * Get the version of the server this agent is connected to. Will be * <code>null</code> until connected. * * @return server version */ public String getServerVersion() { return serverVersion; } /** * Get the client version. This will be 999.999.999 when running * directly from classes or the agent extension version when * running from deployed version. * * @return client version */ public String getClientVersion() { return AGENT_VERSION; } public MultiplexedConnection getConnection() { return con; } /** * Get the hostname of the Adito proxy * * @return hostname */ public String getAditoHost() { return aditoHostname; } public String getTicket() { return ticket; } /** * Get the port of the Adito proxy * * @return port */ public int getAditoPort() { return aditoPort; } public boolean isSecure() { return isSecure; } /** * Get the username for this session * * @return username */ public String getUsername() { return username; } public void onConnectionClose() { currentState = STATE_DISCONNECTED; if (getConfiguration().isSystemExitOnDisconnect()) { startShutdownProcedure(); } else { getGUI().showDisconnected(); } } public void onConnectionOpen() { currentState = STATE_CONNECTED; } /** * Configure the proxy server using the currently set <i>Local Proxy URL</i> * (set by {@link #setLocalProxyURL(String)}. */ public void configureProxy() { // Configure local proxy support if (localProxyURL != null && !localProxyURL.equals("")) { //$NON-NLS-1$ // #ifdef DEBUG log.info("Configuring HTTP proxy to " + obfuscateURL(localProxyURL.toString())); // #endif String userInfo = localProxyURL.getUserinfo(); String user = ""; //$NON-NLS-1$ String password = ""; //$NON-NLS-1$ if (userInfo != null && !userInfo.equals("")) { //$NON-NLS-1$ int idx = userInfo.indexOf(':'); user = URLDecoder.decode(userInfo); if (idx != -1) { password = URLDecoder.decode(userInfo.substring(idx + 1)); user = URLDecoder.decode(userInfo.substring(0, idx)); } } int port = localProxyURL.getPort(); setDefaultProxyType( localProxyURL.getScheme().equals("https") ? HttpClient.PROXY_HTTPS : HttpClient.PROXY_HTTP); //$NON-NLS-1$ setDefaultProxyHost(localProxyURL.getHost()); setDefaultProxyPort(port == -1 ? 80 : port); if (!user.equals("")) { //$NON-NLS-1$ setDefaultProxyCredentials(new PasswordCredentials(user, password)); } if (localProxyURL.getQueryString() != null) { setDefaultProxyPreferredAuthentication(localProxyURL.getQueryString()); } } if (localProxyURL != null && !localProxyURL.equals("")) { //$NON-NLS-1$ setDefaultProxyAuthenticationPrompt(gui); } // Configure reverse proxy support if (reverseProxyURL != null && !reverseProxyURL.equals("")) { //$NON-NLS-1$ // #ifdef DEBUG log.info("Configuring HTTP reverse proxy to " + obfuscateURL(reverseProxyURL.toString())); // #endif int port = reverseProxyURL.getPort(); setDefaultReverseProxyType( reverseProxyURL.getScheme().equals("https") ? HttpClient.PROXY_HTTPS : HttpClient.PROXY_HTTP); //$NON-NLS-1$ setDefaultReverseProxyHost(reverseProxyURL.getHost()); setDefaultReverseProxyPort(port == -1 ? 80 : port); } } /** * Get the {@link HttpClient} that is being used by this VPN client for * communication with Adito. * * @return http client */ private synchronized HttpClient getHttpClient() { if (client == null) { // #ifdef DEBUG log.info("Creating HttpClient instance"); //$NON-NLS-1$ // #endif client = new HttpClient(aditoHostname, aditoPort, isSecure); client.setAuthenticationPrompt( defaultAuthenticationPrompt != null ? defaultAuthenticationPrompt : getGUI()); if (defaultProxyHost != null && !defaultProxyHost.equals("")) { //$NON-NLS-1$ // #ifdef DEBUG log.info("Configuring proxies for HttpClient instance"); //$NON-NLS-1$ // #endif client.setProxyAuthenticationPrompt(defaultProxyAuthenticationPrompt); client.setProxyHost(defaultProxyHost); client.setProxyPort(defaultProxyPort); client.setProxyType(defaultProxyType); if (defaultProxyCredentials != null && defaultProxyCredentials.getUsername() != null && !defaultProxyCredentials.getUsername().equals("")) { //$NON-NLS-1$ /** * LDP - This used to set preemptive authentication but its * causing problems with NTLM */ client.setProxyCredentials(defaultProxyCredentials); /** * LDP - It seems preemptive might be needed for Basic * authentication. There are lots of users seeing * EOFExceptions after 407 proxy authentication required. */ if ("BASIC".equalsIgnoreCase(defaultProxyPreferredAuthentication)) { client.setProxyPreemptiveAuthentication(true); } } client.setProxyPreferedAuthentication( "AUTO".equalsIgnoreCase(defaultProxyPreferredAuthentication) ? null //$NON-NLS-1$ : defaultProxyPreferredAuthentication); } if (defaultReverseProxyHost != null && !defaultReverseProxyHost.equals("")) { //$NON-NLS-1$ // #ifdef DEBUG log.info("Configuring reverse proxy for HttpClient instance"); //$NON-NLS-1$ // #endif client.setReverseProxyHost(defaultReverseProxyHost); client.setReverseProxyPort(defaultReverseProxyPort); client.setReverseProxyType(defaultReverseProxyType); } } return client; } /** * Constructor preventing direct instantiation. */ public Agent(AgentConfiguration agentConfiguration) { this.agentConfiguration = agentConfiguration; // Forced if (getConfiguration().getGUIClass() != null) { try { gui = (AgentClientGUI) Class.forName(getConfiguration().getGUIClass()).newInstance(); } catch (Exception e) { //#ifdef DEBUG log.error("Failed to create GUI", e); //#endif } } // if (gui == null) { // SWT try { Class.forName("org.eclipse.swt.widgets.Display"); gui = (AgentClientGUI) Class.forName("com.adito.agent.client.gui.swt.SWTSystemTrayGUI") .newInstance(); } catch (Exception e) { //#ifdef DEBUG log.debug("Failed to create SWT GUI", e); //#endif } // if (gui == null) { // JDK6 if (Utils.checkVersion("1.6")) { //$NON-NLS-1$ try { // yay, finally agent tray icon for linux gui = (AgentClientGUI) Class.forName("com.adito.agent.client.gui.awt.JDK6SystemTrayGUI") .newInstance(); } catch (Exception e) { //#ifdef DEBUG log.debug("Failed to create JDK6 GUI", e); //#endif } } // Systray4j if (gui == null && Utils.checkVersion("1.2") && System.getProperty("os.name").startsWith("Windows") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ && !System.getProperty("os.name").startsWith("Windows 98") //$NON-NLS-1$ //$NON-NLS-2$ && !System.getProperty("os.name").startsWith("Windows 95") //$NON-NLS-1$ //$NON-NLS-2$ && !System.getProperty("os.name").startsWith("Windows ME")) { //$NON-NLS-1$ //$NON-NLS-2$ try { gui = (AgentClientGUI) Class.forName("com.adito.agent.client.gui.awt.SystemTrayGUI") .newInstance(); } catch (Exception e) { //#ifdef DEBUG log.debug("Failed to create JDIC GUI", e); //#endif } } // Fallback to basic frame GUI if (gui == null) { try { gui = (AgentClientGUI) Class.forName("com.adito.agent.client.gui.awt.BasicFrameGUI") .newInstance(); } catch (Exception e) { //#ifdef DEBUG log.debug("Failed to create basic GUI", e); //#endif } // No GUI? Probably embedded so use a dummy GUI if (gui == null) { gui = new DummyGUI(); } } } } } // /** // * Get the static instance of the {@link Agent}. // * // * @return instance // */ // public static Agent getVPN() { // if (vpn == null) { // vpn = new Agent(); // } // return vpn; // } /** * Get the current state. Will be one of {@link #STATE_DISCONNECTED} or * {@link #STATE_CONNECTED}. * * @return state */ public int getState() { return currentState; } /** * Get the object the stores various configuration options * * @return configuration */ public AgentConfiguration getConfiguration() { return agentConfiguration; } /* * (non-Javadoc) * * @see com.adito.vpn.base.AbstractVPNClient#init(java.lang.String, * int, java.lang.String, java.lang.String) */ public void init() throws SecurityException, IOException { // Create connection object now so users of API can add connection listeners before connecting con = new MultiplexedConnection(new AgentChannelFactory(this)); // #ifdef DEBUG log.info("Allow untrusted hosts is set to " //$NON-NLS-1$ + System.getProperty("com.maverick.ssl.allowUntrustedCertificates", "false")); //$NON-NLS-1$ log.info("Cache directory is " + getConfiguration().getCacheDir()); // #endif // #ifdef DEBUG log.info("Initialising GUI"); //$NON-NLS-1$ // #endif gui.init(this); disconnected(); // Install and configure HTTP / HTTPS support // #ifdef DEBUG log.info("Installing Maverick SSL support for HTTPSURLStreamHandler"); //$NON-NLS-1$ // #endif try { HttpsURLStreamHandlerFactory.addHTTPSSupport(); configureProxy(); } catch (SecurityException se) { disconnected(); throw se; } catch (IOException ioe) { disconnected(); throw ioe; } } public void connect(String aditoHostname, int aditoPort, boolean isSecure, String username, String ticket, boolean ticketIsPassword) throws IOException, HttpException, UnsupportedAuthenticationException, AuthenticationCancelledException { this.aditoHostname = aditoHostname; this.aditoPort = aditoPort; this.username = username; this.ticket = ticket; this.ticketIsPassword = ticketIsPassword; this.isSecure = isSecure; inactivityMonitor = new TunnelInactivityMonitor(this); keepAlive = new KeepAliveThread(); gui.showTxRx(); connectAgent(); // Start the Tx/Rx monitor so we have some animated icons txm = new TXRXMonitor(this); txm.start(); gui.showIdle(); updateInformation(); inactivityMonitor.start(); if (getConfiguration().getKeepAlivePeriod() > 0) keepAlive.start(); if (getConfiguration().isDisplayInformationPopups()) { getGUI().popup(null, Messages.getString("VPNClient.nowRunning"), //$NON-NLS-1$ Messages.getString("VPNClient.title"), "popup-agent", 5000); //$NON-NLS-1$ } try { // Give the popup message some breathing space // otherwise in SWT we loose it :( Thread.sleep(3000); } catch (InterruptedException ex) { } } public boolean processRequest(Request request, MultiplexedConnection con) { if (request.getRequestName().equals(SHUTDOWN_REQUEST)) { disconnectAgent(); return true; } else if (request.getRequestName().equals(MESSAGE_REQUEST)) { displayMessage(request); return true; } else if (request.getRequestName().equals(UPDATE_RESOURCES_REQUEST)) { final ByteArrayReader bar = new ByteArrayReader(request.getRequestData()); Thread t = new Thread() { public void run() { try { updateResources((int) bar.readInt()); } catch (IOException e) { } } }; t.start(); return true; } else if (request.getRequestName().equals(OPEN_URL_REQUEST) && request.getRequestData() != null) { try { ByteArrayReader msg = new ByteArrayReader(request.getRequestData()); openURL(msg.readString(), msg.readString(), request); return true; } catch (IOException e) { // #ifdef DEBUG log.error("Failed to process openURL request", e); // #endif return false; } } else return false; } public void postReply(MultiplexedConnection connection) { } private void displayMessage(Request request) { try { if (request.getRequestData() != null) { ByteArrayReader msg = new ByteArrayReader(request.getRequestData()); String title = msg.readString(); msg.readInt(); // type String message = msg.readString(); getGUI().popup(null, MessageFormat.format(Messages.getString("Agent.received"), new Object[] { SimpleDateFormat.getDateTimeInstance().format(new Date()), message }), title.equals("") ? Messages.getString("Agent.promptTitle") : title, "popup-mail", 0); } } catch (IOException e) { // #ifdef DEBUG log.error("Failed to read message data from popup message request", e); // #endif } } private boolean openURL(String link, String launchId, Request request) { // #ifdef DEBUG log.info("Request to open " + link + " via a temporary tunnel"); //$NON-NLS-1$ //$NON-NLS-2$ // #endif // Parse the link address and create a new address for the browser // to use try { URI url = new URI(link); String linkHost = url.getHost(); int linkPort = url.getPort() == -1 ? (url.getScheme().equalsIgnoreCase("https") ? 443 : 80) //$NON-NLS-1$ : url.getPort(); // Start a tunnel DefaultTunnel t = new DefaultTunnel(-1, TunnelConfiguration.LOCAL_TUNNEL, TunnelConfiguration.TCP_TUNNEL, null, 0, linkPort, linkHost, false, false, linkHost + ":" + linkPort, launchId); LocalTunnelServer listener = getTunnelManager().startLocalTunnel(t); // #ifdef DEBUG log.info("Tunneled web forward listener started on port " + listener.getLocalPort()); // #endif ByteArrayWriter w = new ByteArrayWriter(); w.writeInt(listener.getLocalPort()); request.setRequestData(w.toByteArray()); return true; } catch (Exception e) { // #ifdef DEBUG log.error("Failed to process openURL request", e); // #endif } return false; } /** * Get the current GUI. * * @return gui */ public AgentClientGUI getGUI() { return gui; } public void updateInformation() { // String msg = ""; //$NON-NLS-1$ // int count = getActiveDirectTunnels().size() // + activeForwardingTunnels.size(); // // for (Enumeration e = remoteListeners.elements(); // e.hasMoreElements();) { // MultiplexedConnection con = (MultiplexedConnection) e.nextElement(); // count += con.getActiveChannels().length; // } // int ports = activeListeners.size() + remoteListeners.size(); // if (ports > 0) { // if (count > 0) { // msg = MessageFormat // .format( // Messages // .getString("VPNClient.information.active"), new Object[] { new // Integer(ports), new Integer(count) }); //$NON-NLS-1$ // } else { // msg = MessageFormat // .format( // Messages // .getString("VPNClient.information.notActive"), new Object[] { new // Integer(ports) }); //$NON-NLS-1$ // } // } else if (count > 0) { // msg = MessageFormat // .format( // Messages // .getString("VPNClient.information.remainingConnections"), new // Object[] { new Integer(count) }); //$NON-NLS-1$ // // } // // if (msg.equals("")) { //$NON-NLS-1$ // msg = Messages.getString("VPNClient.information.idle"); //$NON-NLS-1$ // } // // gui.setInfo(msg); } /* * (non-Javadoc) * * @see com.adito.vpn.base.AbstractVPNClient#getTXIOListener() */ public IOStreamConnectorListener getTXIOListener() { return txm != null ? txm.getTxListener() : null; } public IOStreamConnectorListener getRXIOListener() { return txm != null ? txm.getRxListener() : null; } /** * Get the full URL to use for a redirect given the path. The appropriate * hostname and port will automatically be added. * * @param path * path * @return full URL including appropriate host and port */ protected String getRedirectUrl(String path) { try { new URL(path); return path; } catch (Exception e) { return "https://" + getAditoHost() + ":" + getAditoPort() + path; //$NON-NLS-1$ //$NON-NLS-2$ } } protected void startExtensions(String extensionClasses) { StringTokenizer classes = new StringTokenizer(extensionClasses, ","); //$NON-NLS-1$ while (classes.hasMoreTokens()) { String cls = classes.nextToken(); try { Class agent = Class.forName(cls); AgentExtension ext = (AgentExtension) agent.newInstance(); // #ifdef DEBUG log.info("Starting " + ext.getName()); // #endif ext.init(this); extensions.addElement(ext); } catch (Exception e1) { // #ifdef DEBUG log.info("Unable to start extension " + cls, e1); // #endif continue; } } } private void connectAgent() throws IOException, HttpException, UnsupportedAuthenticationException, AuthenticationCancelledException { HttpResponse response = null; HttpAuthenticator authenticator = null; String ticketToSend = ticket; boolean doPreemptive = ticketIsPassword; try { for (int i = 0; i < 3; i++) { HttpClient client = getHttpClient(); if (doPreemptive) { client.setCredentials(new PasswordCredentials(username, ticket)); client.setPreferredAuthentication("Basic"); } else { client.setCredentials(null); } // #ifdef DEBUG log.info("Registering with the server"); //$NON-NLS-1$ log.info("Server is " + (isSecure ? "https://" : "http://") + getAditoHost() //$NON-NLS-1$ + ":" + getAditoPort()); //$NON-NLS-1$ // #endif GetMethod post = new GetMethod("/agent"); //$NON-NLS-1$ client.setPreemtiveAuthentication(doPreemptive); if (!doPreemptive && ticket != null) { post.setParameter("ticket", ticket); //$NON-NLS-1$ } post.setParameter("agentType", getConfiguration().getAgentType()); //$NON-NLS-1$ //$NON-NLS-2$ post.setParameter("locale", Locale.getDefault().toString()); //$NON-NLS-1$ response = client.execute(post); if (response.getStatus() == 302) { // Reset the client this.client = null; URL url = new URL(response.getHeaderField("Location")); //$NON-NLS-1$ aditoHostname = url.getHost(); if (url.getPort() > 0) aditoPort = url.getPort(); continue; } else if (response.getStatus() == 200) { con.addListener(this); httpConnection = response.getConnection(); // Preserve the // connection con.registerRequestHandler(MESSAGE_REQUEST, this); con.registerRequestHandler(SHUTDOWN_REQUEST, this); con.registerRequestHandler(OPEN_URL_REQUEST, this); con.registerRequestHandler(UPDATE_RESOURCES_REQUEST, this); // Start the protocol con.startProtocol(response.getConnection().getInputStream(), response.getConnection().getOutputStream(), true); // Synchronize and read back server information Request syncRequest = new Request(SYNCHRONIZED_REQUEST); con.sendRequest(syncRequest, true); if (syncRequest.getRequestData() == null) throw new IOException("Server failed to return version data"); ByteArrayReader reader = new ByteArrayReader(syncRequest.getRequestData()); serverVersion = reader.readString(); /** * Initialize the managers. Tunnels are no longer recorded * here unless they are active. This simplifies the agent by * making it respond to start and stop requests from the new * persistent connection with Adito. */ tunnelManager = new TunnelManager(this); applicationManager = new ApplicationManager(this); webForwardManager = new WebForwardManager(this); networkPlaceManager = new NetworkPlaceManager(this); updateResources(-1); return; } else if (response.getStatus() == 401) { authenticator = HttpAuthenticatorFactory.createAuthenticator(response.getConnection(), response.getHeaderFields("WWW-Authenticate"), "WWW-Authenticate", "Authorization", HttpAuthenticatorFactory.BASIC, post.getURI()); if (authenticator.wantsPrompt()) { if (!(defaultAuthenticationPrompt != null ? defaultAuthenticationPrompt.promptForCredentials(false, authenticator) : getGUI().promptForCredentials(false, authenticator))) { throw new AuthenticationCancelledException(); } } } else if (response.getStatus() == 403) { if (doPreemptive || ticket != null) { doPreemptive = false; ticket = null; } else { throw new IOException(MessageFormat.format(Messages.getString("VPNClient.register.failed"), new Object[] { String.valueOf(response.getStatus()), response.getReason() })); } } } throw new IOException(Messages.getString("VPNClient.register.tooManyRedirects")); //$NON-NLS-1$ } catch (IOException ioe) { disconnected(); throw ioe; } catch (HttpException httpe) { disconnected(); throw httpe; } catch (UnsupportedAuthenticationException uae) { disconnected(); throw uae; } catch (AuthenticationCancelledException ace) { disconnected(); throw ace; } } public boolean isConnected() { return con != null && con.isRunning(); } public void disconnect() { if (isConnected()) { disconnectAgent(); } } /** * Shutdown the Agent. * * @param deregister * deregister the agent * @param threadDeRegister * deregister in a thread */ public void startShutdownProcedure() { // #ifdef DEBUG log.info("Starting agent shutdown procedure."); //$NON-NLS-1$ // #endif if (getConfiguration().isDisplayInformationPopups()) { getGUI().popup(null, Messages.getString("VPNClient.shutdown.popupText"), //$NON-NLS-1$ Messages.getString("VPNClient.title"), "popup-agent", -1); //$NON-NLS-1$ } AgentExtension ext; for (Enumeration e = extensions.elements(); e.hasMoreElements();) { ext = (AgentExtension) e.nextElement(); // #ifdef DEBUG log.info("Stopping extension " + ext.getName()); //$NON-NLS-1$ // #endif ext.exit(); } getGUI().showDisconnected(); FileCleaner.deleteAllFiles(); if (getConfiguration().isCleanOnExit()) { if (Utils.isSupportedPlatform("Windows")) { cleanupWindowsAgent(); } else if (Utils.isSupportedPlatform("Linux")) { cleanupLinuxAgent(); } else { // #ifdef DEBUG log.info("Agent cleanOnExit is not supported on this platform."); //$NON-NLS-1$ // #endif } } if (getConfiguration().isSystemExitOnDisconnect()) { scheduleExit(); } else { gui.dispose(); } } /** * Get the default credentials used for proxy server authentication. By * default this will be <code>null</code> * * @return default credentials used for proxy server authentication. */ public PasswordCredentials getDefaultProxyCredentials() { return defaultProxyCredentials; } /** * Set the default credentials used for proxy server authentication. * * @param defaultProxyCredentials * default credentials used for proxy server authentication. */ public void setDefaultProxyCredentials(PasswordCredentials defaultProxyCredentials) { this.defaultProxyCredentials = defaultProxyCredentials; } /** * Get the default hostname for the proxy server to use. Use * <code>null</code> for no proxy server (the default). * * @return proxy hostname or <code>null</code> for no proxy */ public String getDefaultProxyHost() { return defaultProxyHost; } /** * Set the default hostname for the proxy server to use. Use * <code>null</code> for no proxy server (the default). * * @param defaultProxyHost * proxy hostname or <code>null</code> for no proxy */ public void setDefaultProxyHost(String defaultProxyHost) { this.defaultProxyHost = defaultProxyHost; } /** * Get the default hostname for the reverse proxy server to use. Use * <code>null</code> for no proxy server (the default). * * @return reverse proxy hostname or <code>null</code> for no proxy */ public String getDefaultReverseProxyHost() { return defaultReverseProxyHost; } /** * Set the default hostname for the reverse proxy server to use. Use * <code>null</code> for no proxy server (the default). * * @param defaultReverseProxyHost * reverse proxy hostname or <code>null</code> for no proxy */ public void setDefaultReverseProxyHost(String defaultReverseProxyHost) { this.defaultReverseProxyHost = defaultReverseProxyHost; } /** * Set the default proxy port. By default this is <i>80</i>. * * CHECK Why 80? IIS? * * @return default proxy port number */ public int getDefaultProxyPort() { return defaultProxyPort; } /** * Set the default proxy port. By default this is <i>80</i>. * * CHECK Why 80? IIS? * * @param defaultProxyPort * default proxy port number */ public void setDefaultProxyPort(int defaultProxyPort) { this.defaultProxyPort = defaultProxyPort; } /** * Set the default reverse proxy port. By default this is <i>80</i>. * * CHECK Why 80? IIS? * * @return default reverse proxy port number */ public int getDefaultReverseProxyPort() { return defaultReverseProxyPort; } /** * Set the default reverse proxy port. By default this is <i>80</i>. * * CHECK Why 80? IIS? * * @param defaultReverseProxyPort * default reverse proxy port number */ public void setDefaultReverseProxyPort(int defaultReverseProxyPort) { this.defaultReverseProxyPort = defaultReverseProxyPort; } /** * Get the default proxy type. This may be one of * {@link HttpClient#PROXY_HTTP}, {@link HttpClient#PROXY_HTTPS} or * {@link HttpClient#PROXY_NONE}. By default this is * {@link HttpClient#PROXY_HTTP}. * * @return default proxy type */ public int getDefaultProxyType() { return defaultProxyType; } /** * Set the default proxy type. This may be one of * {@link HttpClient#PROXY_HTTP}, {@link HttpClient#PROXY_HTTPS} or * {@link HttpClient#PROXY_NONE}. By default this is * {@link HttpClient#PROXY_HTTP}. * * @param defaultProxyType * default proxy type */ public void setDefaultProxyType(int defaultProxyType) { this.defaultProxyType = defaultProxyType; } /** * Get the default reverse proxy type. This may be one of * {@link HttpClient#PROXY_HTTP}, {@link HttpClient#PROXY_HTTPS} or * {@link HttpClient#PROXY_NONE}. By default this is * {@link HttpClient#PROXY_HTTP}. * * @return default reverse proxy type */ public int getDefaultReverseProxyType() { return defaultReverseProxyType; } /** * Set the default reverse proxy type. This may be one of * {@link HttpClient#PROXY_HTTP}, {@link HttpClient#PROXY_HTTPS} or * {@link HttpClient#PROXY_NONE}. By default this is * {@link HttpClient#PROXY_HTTP}. * * @param defaultReverseProxyType * default reverse proxy type */ public void setDefaultReverseProxyType(int defaultReverseProxyType) { this.defaultReverseProxyType = defaultReverseProxyType; } /** * Get the default preferred authentication type to use for proxy servers. * This may be one of {@link HttpAuthenticatorFactory#BASIC}, * {@link HttpAuthenticatorFactory#NTLM}, * {@link HttpAuthenticatorFactory#DIGEST}, * {@link HttpAuthenticatorFactory#NONE} or <code>null</code> (Automatic). * The string value <i>"AUTO"</i> may be used instead of <code>null</code>. * * @return default proxy authentication type */ public String getDefaultProxyPreferredAuthentication() { return defaultProxyPreferredAuthentication; } /** * Set the default preferred authentication type to use for proxy servers. * This may be one of {@link HttpAuthenticatorFactory#BASIC}, * {@link HttpAuthenticatorFactory#NTLM}, * {@link HttpAuthenticatorFactory#DIGEST}, * {@link HttpAuthenticatorFactory#NONE} or <code>null</code> (Automatic). * The string value <i>"AUTO"</i> may be used instead of <code>null</code>. * * @param defaultProxyPreferredAuthentication * default proxy authentication type */ public void setDefaultProxyPreferredAuthentication(String defaultProxyPreferredAuthentication) { this.defaultProxyPreferredAuthentication = defaultProxyPreferredAuthentication; } /** * Get the {@link AuthenticationPrompt} that will be used if the proxy * server requires authentication. This may happen if the default * authentication details have not been set using the methods in the class * or if those details are incorrect and the proxy server is requesting * again. * <p> * The prompt may for example display a GUI dialog box that will ask the * user for details or it may retrieve them from somewhere else such as a * password database. * <p> * If <code>null</code> is returned then no authenitcation prompt is set. * * @return authentication prompt */ public AuthenticationPrompt getDefaultProxyAuthenticationPrompt() { return defaultProxyAuthenticationPrompt; } /** * Set the {@link AuthenticationPrompt} that will be used if the proxy * server requires authentication. This may happen if the default * authentication details have not been set using the methods in the class * or if those details are incorrect and the proxy server is requesting * again. * <p> * The prompt may for example display a GUI dialog box that will ask the * user for details or it may retrieve them from somewhere else such as a * password database. * <p> * If <code>null</code> is returned then no authenitcation prompt is set. * * @param defaultProxyAuthenticationPrompt * authentication prompt */ public void setDefaultProxyAuthenticationPrompt(AuthenticationPrompt defaultProxyAuthenticationPrompt) { this.defaultProxyAuthenticationPrompt = defaultProxyAuthenticationPrompt; } /** * Set the {@link AuthenticationPrompt} that will be used if the Adito * server requires authentication. This may happen if the default * authentication details have not been set using the methods in the class * or if those details are incorrect and the server is requesting * again. * <p> * The prompt may for example display a GUI dialog box that will ask the * user for details or it may retrieve them from somewhere else such as a * password database. * * @param defaultAuthenticationPrompt * authentication prompt */ public void setDefaultAuthenticationPrompt(AuthenticationPrompt defaultAuthenticationPrompt) { this.defaultAuthenticationPrompt = defaultAuthenticationPrompt; } /** * Utility method to hide any passwords that may be present in the userinfo * portion of a URL. * * @param originalUrl * original url * @return obfuscated url */ public static String obfuscateURL(String originalUrl) { try { URI url = new URI(originalUrl); String userInfo = url.getUserinfo(); String user = ""; //$NON-NLS-1$ if (userInfo != null && !userInfo.equals("")) { //$NON-NLS-1$ int idx = userInfo.indexOf(':'); user = userInfo; if (idx != -1) { user = userInfo.substring(0, idx); } return url.getScheme() + "://" + user + ":***@" + url.getHost() + ":" + url.getPort() //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + (url.getQueryString() != null ? ("?" + url.getQueryString()) : ""); //$NON-NLS-1$ //$NON-NLS-2$ } else { return originalUrl; } } catch (URI.MalformedURIException e) { return originalUrl; } } /** * Get a <code>Properties</code> that may be sent back to the server so it * can check if the client is in a supported environment. For example, the * sun.os.patch.level property may be used to deny clients that are running * Windows SP1. * * @return system properties */ public static Properties getSystemPropertiesToSend() { Properties p = new Properties(); setIfNotEmpty("java.version", p); //$NON-NLS-1$ setIfNotEmpty("java.vendor", p); //$NON-NLS-1$ setIfNotEmpty("sun.os.patch.level", p); //$NON-NLS-1$ setIfNotEmpty("os.name", p); //$NON-NLS-1$ setIfNotEmpty("os.version", p); //$NON-NLS-1$ setIfNotEmpty("os.arch", p); //$NON-NLS-1$ return p; } protected static void setIfNotEmpty(String name, Properties p) { String v = System.getProperty(name); if (v != null && !v.equals("")) { //$NON-NLS-1$ p.put(name, v); } } private static String getCommandLineValue(String arg) { int idx = arg.indexOf('='); if (idx > -1) return arg.substring(idx + 1); else return arg; } /** * Entry point. * * @param args arguments */ public static void main(String[] args) throws Throwable { try { // #ifdef DEBUG org.apache.log4j.BasicConfigurator.configure(); // #endif AgentArgs agentArgs = Agent.initArgs(args); Agent agent = Agent.initAgent(agentArgs); if (agentArgs.isDisableNewSSLEngine()) SSLTransportFactory.setTransportImpl(SSLTransportImpl.class); agent.initMain(agentArgs.getHostname(), agentArgs.getPort(), agentArgs.isSecure(), agentArgs.getUsername(), agentArgs.getPassword(), agentArgs.getTicket()); if (agentArgs.getExtensionClasses() != null) agent.startExtensions(agentArgs.getExtensionClasses()); } catch (Throwable t) { // Catch any nasties to make sure we exit // #ifdef DEBUG if (log != null) { log.error("Critical error, shutting down.", t); //$NON-NLS-1$ } else { System.err.println("Critical error, shutting down."); t.printStackTrace(); } // #endif throw t; } } protected static AgentArgs initArgs(String[] args) throws Throwable { int shutdown = -1; int webforwardInactivity = 300000; int tunnelInactivity = 600000; AgentArgs agentArgs = new AgentArgs(); AgentConfiguration configuration = new AgentConfiguration(); String hostHeader = null; String protocol = null; for (int i = 0; i < args.length; i++) { if (args[i].startsWith("host")) { //$NON-NLS-1$ hostHeader = getCommandLineValue(args[i]); } else if (args[i].startsWith("protocol")) { //$NON-NLS-1$ protocol = getCommandLineValue(args[i]); } else if (args[i].startsWith("username")) { //$NON-NLS-1$ agentArgs.setUsername(getCommandLineValue(args[i])); } else if (args[i].startsWith("password")) { //$NON-NLS-1$ agentArgs.setPassword(getCommandLineValue(args[i])); } else if (args[i].startsWith("localProxyURL")) { //$NON-NLS-1$ agentArgs.setLocalProxyURL(getCommandLineValue(args[i])); } else if (args[i].startsWith("reverseProxyURL")) { //$NON-NLS-1$ agentArgs.setReverseProxyURL(getCommandLineValue(args[i])); } else if (args[i].startsWith("pluginProxyURL")) { //$NON-NLS-1$ agentArgs.setPluginProxyURL(getCommandLineValue(args[i])); } else if (args[i].startsWith("ticket")) { //$NON-NLS-1$ agentArgs.setTicket(getCommandLineValue(args[i])); } else if (args[i].startsWith("browserCommand")) { //$NON-NLS-1$ agentArgs.setBrowserCommand(getCommandLineValue(args[i])); } else if (args[i].startsWith("userAgent")) { //$NON-NLS-1$ String userAgent = getCommandLineValue(args[i]); agentArgs.setUserAgent(userAgent); HttpClient.setUserAgent(userAgent); } else if (args[i].startsWith("locale")) { //$NON-NLS-1$ agentArgs.setLocaleName(getCommandLineValue(args[i])); } else if (args[i].startsWith("disableNewSSLEngine")) { //$NON-NLS-1$ agentArgs.setDisableNewSSLEngine(Boolean.valueOf(getCommandLineValue(args[i])).booleanValue()); } else if (args[i].startsWith("webforward.inactivity")) { //$NON-NLS-1$ try { webforwardInactivity = Integer.parseInt(getCommandLineValue(args[i])); } catch (NumberFormatException ex) { } } else if (args[i].startsWith("tunnel.inactivity")) { //$NON-NLS-1$ try { tunnelInactivity = Integer.parseInt(getCommandLineValue(args[i])); } catch (NumberFormatException ex) { } } else if (args[i].startsWith("shutdown")) { //$NON-NLS-1$ try { shutdown = Integer.parseInt(getCommandLineValue(args[i])); } catch (NumberFormatException ex) { } } else if (args[i].startsWith("log4j")) { //$NON-NLS-1$ agentArgs.setLogProperties(getCommandLineValue(args[i])); } else if (args[i].startsWith("extensionClasses")) { //$NON-NLS-1$ agentArgs.setExtensionClasses(getCommandLineValue(args[i])); } else if (args[i].startsWith("ignoreCertWarnings")) { System.getProperties().put("com.maverick.ssl.allowUntrustedCertificates", "true"); System.getProperties().put("com.maverick.ssl.allowInvalidCertificates", "true"); } else if (args[i].startsWith("forceBasicUI")) { configuration.setGUIClass("com.adito.agent.client.gui.BasicFrameGUI"); } else if (args[i].startsWith("displayInformationPopups")) { configuration.setDisplayInformationPopups(getCommandLineValue(args[i]).equalsIgnoreCase("true")); } else if (args[i].startsWith("remoteTunnelsRequireConfirmation")) { configuration .setRemoteTunnelsRequireConfirmation(getCommandLineValue(args[i]).equalsIgnoreCase("true")); } else if (args[i].startsWith("cleanOnExit")) { configuration.setCleanOnExit(getCommandLineValue(args[i]).equalsIgnoreCase("true")); } else if (args[i].startsWith("localhostAddress")) { configuration.setLocalhostAddress(getCommandLineValue(args[i])); } else if (args[i].startsWith("dir")) { configuration.setCacheDir(new File(Utils.getHomeDirectory(), getCommandLineValue(args[i]))); } else if (args[i].startsWith("removeFiles")) { StringTokenizer files = new StringTokenizer(getCommandLineValue(args[i]), File.pathSeparator); while (files.hasMoreTokens()) { configuration.removeFileOnExit(new File(files.nextToken())); } } else if (args[i].startsWith("keepAlivePeriod")) { configuration.setKeepAlivePeriod(Integer.parseInt(getCommandLineValue(args[i]))); } else if (args[i].startsWith("extensionId")) { agentArgs.setExtensionId(getCommandLineValue(args[i])); } } if (hostHeader == null || protocol == null) { throw new IOException(""); } else { int idx = hostHeader.indexOf(':'); if (idx > -1) { String port = hostHeader.substring(idx + 1); agentArgs.setHostname(hostHeader.substring(0, idx)); try { agentArgs.setPort(Integer.parseInt(port)); } catch (NumberFormatException ex) { } agentArgs.setSecure(protocol.equalsIgnoreCase("https")); } else { agentArgs.setHostname(hostHeader); agentArgs.setPort(protocol.equalsIgnoreCase("http") ? 80 : 443); agentArgs.setSecure(protocol.equalsIgnoreCase("https")); } } if (isWindows64()) { configuration.setGUIClass("com.adito.agent.client.gui.BasicFrameGUI"); } WinRegistry.setLocation(new File(configuration.getCacheDir(), "applications" + File.separator + agentArgs.getExtensionId())); /* * Load the message resources. */ Locale.setDefault(Utils.createLocale(agentArgs.getLocaleName())); if (agentArgs.getLogProperties() == null) { System.out.println(Messages.getString("VPNClient.main.debugModeWarning")); //$NON-NLS-1$ } if (agentArgs.getPort() == -1 || agentArgs.getHostname() == null || agentArgs.getUsername() == null || (agentArgs.getTicket() == null && agentArgs.getPassword() == null)) throw new IOException(Messages.getString("VPNClient.main.missingCommandLineArguments")); //$NON-NLS-1$ if (shutdown > -1) configuration.setShutdownPeriod(shutdown); configuration.setSystemExitOnDisconnect(true); configuration.setWebForwardInactivity(webforwardInactivity); configuration.setTunnelInactivity(tunnelInactivity); agentArgs.setAgentConfiguration(configuration); return agentArgs; } protected static Agent initAgent(AgentArgs agentArgs) throws Throwable { Agent agent = new Agent(agentArgs.getAgentConfiguration()); // Setup the output stream PrintStream consolePrintStream = new PrintStream(agent.getGUI().getConsole()); System.setErr(consolePrintStream); System.setOut(consolePrintStream); System.out.println("Java version " + System.getProperty("java.version")); System.out.println("OS version " + System.getProperty("os.name")); // #ifdef DEBUG if (agentArgs.getLogProperties() != null) { File f = new File(agentArgs.getLogProperties()); InputStream in = new FileInputStream(f); try { Properties props = new Properties(); props.load(in); File logfile = new File(f.getParent(), "agent.log"); //$NON-NLS-1$ props.put("log4j.appender.logfile.File", logfile.getAbsolutePath()); //$NON-NLS-1$ org.apache.log4j.PropertyConfigurator.configure(props); log = org.apache.commons.logging.LogFactory.getLog(Agent.class); log.info("Configured logging"); //$NON-NLS-1$ } finally { in.close(); } } Properties systemProperties = System.getProperties(); String key; log.info("System properties:"); for (Enumeration e = systemProperties.keys(); e.hasMoreElements();) { key = (String) e.nextElement(); log.info(" " + key + ": " + systemProperties.getProperty(key)); } // #endif agent.setupProxy(agentArgs.getLocalProxyURL(), agentArgs.getUserAgent(), agentArgs.getPluginProxyURL(), agentArgs.getReverseProxyURL()); if (agentArgs.getBrowserCommand() != null && !agentArgs.getBrowserCommand().equals("")) { //$NON-NLS-1$ // #ifdef DEBUG log.info("Setting browser to " + agentArgs.getBrowserCommand()); //$NON-NLS-1$ // #endif BrowserLauncher.setBrowserCommand(agentArgs.getBrowserCommand()); } return agent; } private static boolean isWindows64() { String prop = System.getProperty("os.name"); if (prop == null || prop.startsWith("Windows") == false) return false; prop = System.getProperty("os.arch"); if (prop != null && prop.equalsIgnoreCase("amd64")) return true; prop = System.getProperty("java.vm.name"); if (prop != null && prop.indexOf("64-Bit") != -1) return true; prop = System.getProperty("sun.arch.data.model"); if (prop != null && prop.equals("64")) return true; return false; } private static boolean isWindowsVista() { return System.getProperty("os.name").startsWith("Windows Vista"); } public static void initMain(Agent agent, AgentArgs agentArgs) { if (null != agent && null != agentArgs) { agent.initMain(agentArgs.getHostname(), agentArgs.getPort(), agentArgs.isSecure(), agentArgs.getUsername(), agentArgs.getPassword(), agentArgs.getTicket()); if (agentArgs.getExtensionClasses() != null) agent.startExtensions(agentArgs.getExtensionClasses()); } } protected void initMain(String hostname, int port, boolean isSecure, String username, String password, String ticket) { try { init(); connect(hostname, port, isSecure, username, ticket == null ? password : ticket, ticket == null); } catch (SSLIOException ex) { // #ifdef DEBUG log.info("An unexpected SSL IO error has occured.", ex.getRealException()); //$NON-NLS-1$ log.info("Agent will now exit."); //$NON-NLS-1$ // #endif gui.showDisconnected(); if (getConfiguration().isDisplayInformationPopups()) { gui.error(Messages.getString("VPNClient.close"), null, //$NON-NLS-1$ Messages.getString("VPNClient.error"), //$NON-NLS-1$ Messages.getString("VPNClient.failedToConnect"), ex); //$NON-NLS-1$ } else { try { // Show Disconnected State for 1 second before losing it (if no pop-up) Thread.sleep(1000); } catch (InterruptedException slp) { } } gui.dispose(); System.exit(4); } catch (IOException ex) { // #ifdef DEBUG log.info("An unexpected IO error has occured.", ex); //$NON-NLS-1$ log.info("Agent will now exit."); //$NON-NLS-1$ // #endif gui.showDisconnected(); if (getConfiguration().isDisplayInformationPopups()) { gui.error(Messages.getString("VPNClient.close"), null, //$NON-NLS-1$ Messages.getString("VPNClient.error"), //$NON-NLS-1$ Messages.getString("VPNClient.failedToConnect"), ex); //$NON-NLS-1$ } else { try { // Show Disconnected State for 1 second before losing it (if no pop-up) Thread.sleep(1000); } catch (InterruptedException slp) { } } gui.dispose(); System.exit(4); } catch (Throwable t) { gui.error(Messages.getString("VPNClient.close"), null, //$NON-NLS-1$ Messages.getString("VPNClient.error"), //$NON-NLS-1$ Messages.getString("VPNClient.failedToConnect"), t); //$NON-NLS-1$ // #ifdef DEBUG log.info("Critical failure", t); //$NON-NLS-1$ // #endif gui.showDisconnected(); System.exit(4); } } public void setupProxy(String localProxyURL, String userAgent, String pluginProxyURL, String reverseProxyURL) throws MalformedURIException { if (localProxyURL != null && !localProxyURL.equals("") && !localProxyURL.startsWith("browser://")) { //$NON-NLS-1$ //$NON-NLS-2$ // Use the user supplied proxy settings // #ifdef DEBUG log.info("Setting user specified local proxy URL to " + obfuscateURL(localProxyURL)); //$NON-NLS-1$ // #endif setLocalProxyURL(localProxyURL); } else { // #ifdef DEBUG log.info("Attempting to detect proxy settings using platform specific methods"); //$NON-NLS-1$ // #endif if (localProxyURL != null && localProxyURL.startsWith("browser://")) { //$NON-NLS-1$ URI uri = new URI(localProxyURL); /* * Try to determine the proxy settings by first usng platform / * browser specific method, then the proxy supplied by the Java * plugin. * * TODO be more intelligent about which browse to try first - * use the userAgent parameter passed from the JSP */ String proxyURL = null; if (userAgent != null) { // TODO support more browsers BrowserProxySettings proxySettings = null; if (userAgent.indexOf("MSIE") != -1) { //$NON-NLS-1$ try { // #ifdef DEBUG log.info("Looking for IE"); //$NON-NLS-1$ // #endif proxySettings = ProxyUtil.lookupIEProxySettings(); } catch (Throwable t) { // #ifdef DEBUG log.error("Failed to get IE proxy settings, trying Firefox.", t); //$NON-NLS-1$ // #endif } } if (proxySettings == null && userAgent.indexOf("Firefox") != -1) { //$NON-NLS-1$ try { // #ifdef DEBUG log.info("Looking for Firefox"); //$NON-NLS-1$ // #endif proxySettings = ProxyUtil.lookupFirefoxProxySettings(); } catch (Throwable t) { // #ifdef DEBUG log.error("Failed to get Firefox proxy settings.", t); //$NON-NLS-1$ // #endif } } if (proxySettings != null) { // #ifdef DEBUG log.info("Found some proxy settings."); //$NON-NLS-1$ // #endif ProxyInfo[] proxyInfo = proxySettings.getProxies(); for (int i = 0; proxyInfo != null && i < proxyInfo.length; i++) { // #ifdef DEBUG log.info("Checking if " + obfuscateURL(proxyInfo[i].toUri()) + " is suitable."); //$NON-NLS-1$ // #endif if (proxyInfo[i].getProtocol().equals("ssl") //$NON-NLS-1$ || proxyInfo[i].getProtocol().equals("https") //$NON-NLS-1$ || proxyInfo[i].getProtocol().equals("all")) { //$NON-NLS-1$ StringBuffer buf = new StringBuffer("http://"); //$NON-NLS-1$ if (proxyInfo[i].getUsername() != null && !proxyInfo[i].getUsername().equals("")) { //$NON-NLS-1$ buf.append(proxyInfo[i].getUsername()); if (proxyInfo[i].getPassword() != null && !proxyInfo[i].getPassword().equals("")) { //$NON-NLS-1$ buf.append(":"); //$NON-NLS-1$ buf.append(proxyInfo[i].getPassword()); } buf.append("@"); //$NON-NLS-1$ } buf.append(proxyInfo[i].getHostname()); if (proxyInfo[i].getPort() != 0) { buf.append(":"); //$NON-NLS-1$ buf.append(proxyInfo[i].getPort()); } if (uri.getHost() != null) { buf.append("?"); //$NON-NLS-1$ buf.append(uri.getHost()); } proxyURL = buf.toString(); break; } } } else { // #ifdef DEBUG log.warn("No useragent supplied, automatic proxy could not check for browse type."); //$NON-NLS-1$ // #endif } // Use the proxy supplied by the plugin if it is // available if (proxyURL == null && pluginProxyURL != null && !pluginProxyURL.equals("")) { //$NON-NLS-1$ // #ifdef DEBUG log.info("Using plugin supplied proxy settings."); //$NON-NLS-1$ // #endif proxyURL = pluginProxyURL; } } if (proxyURL != null) { // #ifdef DEBUG log.info("Setting local proxy URL to " + obfuscateURL(proxyURL) + "."); //$NON-NLS-1$ // #endif setLocalProxyURL(proxyURL); } } } if (reverseProxyURL != null && !reverseProxyURL.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$ // Use the user supplied reverse proxy settings // #ifdef DEBUG log.info("Setting user specified reverse proxy URL to " + obfuscateURL(reverseProxyURL)); //$NON-NLS-1$ // #endif setReverseProxyURL(reverseProxyURL); } } private void cleanupWindowsAgent() { // #ifdef DEBUG log.info("Clearing Windows agent cache"); //$NON-NLS-1$ // #endif try { String[] cmds = null; String homeDir = Utils.getHomeDirectory(); File cwd = getConfiguration().getCacheDir(); // #ifdef DEBUG log.info("Will remove " + cwd.getAbsolutePath()); //$NON-NLS-1$ // #endif File scriptFile = new File(homeDir, "agent-cleanup.bat"); File launchFile = new File(homeDir, "agent-cleanup-launch.bat"); String scriptContents = "@echo off\r\n" + "echo Agent is removing all downloaded files\r\n" + ":Repeat\r\n" + "rd /S /Q \"" + cwd.getAbsolutePath() + "\" > NUL 2>&1\r\n" + "if exist \"" + cwd.getAbsolutePath() + "\" > NUL 2>&1 goto Repeat\r\n"; File toRemove; for (Enumeration e = getConfiguration().getFilesToRemove(); e.hasMoreElements();) { toRemove = (File) e.nextElement(); if (toRemove.exists()) { if (toRemove.isDirectory()) { scriptContents += "rd /S /Q \"" + toRemove.getAbsolutePath() + "\" > NUL 2>&1\r\n"; } else { scriptContents += "del \"" + toRemove.getAbsolutePath() + "\" > NUL 2>&1\r\n"; } } } scriptContents += "del \"" + scriptFile.getAbsolutePath() + "\" > NUL 2>&1 && exit\r\n"; String launchScript = "start \"Agent Cleanup\" /MIN \"" + scriptFile.getAbsolutePath() + "\"\r\n" + "del \"" + launchFile.getAbsolutePath() + "\" > NUL 2>&1\r\n"; cmds = new String[3]; cmds[0] = "cmd.exe"; cmds[1] = "/C"; cmds[2] = "\"" + launchFile.getAbsolutePath() + "\""; FileOutputStream out = new FileOutputStream(scriptFile); out.write(scriptContents.getBytes()); out.close(); out = new FileOutputStream(launchFile); out.write(launchScript.getBytes()); out.close(); final Process proc = Runtime.getRuntime().exec(cmds); Thread t1 = new Thread(new Runnable() { public void run() { try { InputStream in = proc.getInputStream(); while (in.read() > -1) ; } catch (IOException e) { } } }, "CleanupAgentInput"); Thread t2 = new Thread(new Runnable() { public void run() { try { InputStream in = proc.getErrorStream(); while (in.read() > -1) ; } catch (IOException e) { } } }, "CleanupAgentOutput"); t1.start(); t2.start(); } catch (Exception e) { } } /** * Schedule a System.exit() in a thread. After the configured shutdown * period has elapsed the JVM will terminate. */ public void scheduleExit() { Thread t = new Thread("ScheduledExit") { public void run() { try { Thread.sleep(getConfiguration().getShutdownPeriod()); } catch (InterruptedException ex) { } gui.dispose(); // #ifdef DEBUG log.info("Exiting JVM."); //$NON-NLS-1$ // #endif System.exit(0); } }; t.start(); } private void disconnected() { currentState = STATE_DISCONNECTED; getGUI().showDisconnected(); } private void disconnectAgent() { // #ifdef DEBUG log.info("Disconnecting Agent"); //$NON-NLS-1$ // #endif // Disconnect the multiplexed protocol keepAlive.stopThread(); con.disconnect("The agent is shutting down"); // This is a backup to ensure that the socket is released. httpConnection.close(); } private void cleanupLinuxAgent() { // #ifdef DEBUG log.info("Clearing Linux agent cache"); //$NON-NLS-1$ // #endif try { String[] cmds = null; String homeDir = Utils.getHomeDirectory(); File cacheDir = getConfiguration().getCacheDir(); // #ifdef DEBUG log.info("Will remove " + cacheDir.getAbsolutePath()); //$NON-NLS-1$ // #endif File scriptFile = new File(homeDir, "agent-cleanup.sh"); File launchFile = new File(homeDir, "agent-cleanup-launch.sh"); // clean up script StringBuffer scriptContents = new StringBuffer(); scriptContents.append("#!/bin/sh\n"); scriptContents.append("sleep 3\n"); scriptContents.append("rm -fr \""); scriptContents.append(cacheDir.getAbsolutePath()); scriptContents.append("\" \""); File toRemove; for (Enumeration e = getConfiguration().getFilesToRemove(); e.hasMoreElements();) { toRemove = (File) e.nextElement(); scriptContents.append(toRemove.getAbsolutePath()); scriptContents.append("\" \""); } scriptContents.append(scriptFile.getAbsolutePath()); scriptContents.append("\" \""); scriptContents.append(launchFile.getAbsolutePath()); scriptContents.append("\"\n"); // launch script StringBuffer launchScript = new StringBuffer(); launchScript.append("#!/bin/sh\n"); launchScript.append("nohup sh \""); launchScript.append(scriptFile.getAbsolutePath()); launchScript.append("\" &\n"); cmds = new String[2]; cmds[0] = "sh"; cmds[1] = launchFile.getAbsolutePath(); FileOutputStream out = new FileOutputStream(scriptFile); out.write(scriptContents.toString().getBytes()); out.close(); out = new FileOutputStream(launchFile); out.write(launchScript.toString().getBytes()); out.close(); final Process proc = Runtime.getRuntime().exec(cmds); Thread t1 = new Thread(new Runnable() { public void run() { try { InputStream in = proc.getInputStream(); while (in.read() > -1) ; } catch (IOException e) { } } }); Thread t2 = new Thread(new Runnable() { public void run() { try { InputStream in = proc.getErrorStream(); while (in.read() > -1) ; } catch (IOException e) { } } }); t1.start(); t2.start(); } catch (Exception e) { } } protected void updateResources(int resourceTypeId) { if (getConfiguration().isGetResources()) { /* TODO we should consider moving the services into the appropriate extension instead * of all in the agent module. It should now be possible to rewrite them as agent * extensions */ // Applications if (resourceTypeId == -1 || resourceTypeId == ApplicationManager.APPLICATION_SHORTCUT_RESOURCE_TYPE_ID) applicationManager.getApplicationResources(); // Tunnels if (resourceTypeId == -1 || resourceTypeId == TunnelManager.TUNNEL_RESOURCE_TYPE_ID) tunnelManager.getTunnelResources(); // Web forwards if (resourceTypeId == -1 || resourceTypeId == WebForwardManager.WEBFORWARD_RESOURCE_TYPE_ID) webForwardManager.getWebForwardResources(); // Network places if (resourceTypeId == -1 || resourceTypeId == NetworkPlaceManager.NETWORK_PLACE_RESOURCE_TYPE_ID) networkPlaceManager.getNetworkPlaceResources(); } } class KeepAliveThread extends Thread { boolean running = true; Request keepAlive = new Request("keepAlive"); public void run() { long period = getConfiguration().getKeepAlivePeriod(); if (period > 0) { while (running && con.isRunning()) { try { Thread.sleep(period); } catch (InterruptedException e) { } if (!running || !con.isRunning()) { break; } try { con.sendRequest(keepAlive, true, getConfiguration().getKeepAliveTimeout()); } catch (InterruptedIOException ex) { //#ifdef DEBUG log.error("Keepalive packet timed out!! Agent connection is no longer operational", ex); //#endif if (getConfiguration().isDisplayInformationPopups()) { getGUI().popup(null, Messages.getString("VPNClient.keepalive.timeout"), //$NON-NLS-1$ Messages.getString("VPNClient.title"), "popup-error", -1); //$NON-NLS-1$ } try { Thread.sleep(10000); } catch (InterruptedException e) { } Agent.this.startShutdownProcedure(); } catch (IOException e) { //#ifdef DEBUG log.error("Keepalive IO error!! Agent connection is no longer operational", e); //#endif if (getConfiguration().isDisplayInformationPopups()) { getGUI().popup(null, Messages.getString("VPNClient.keepalive.error"), //$NON-NLS-1$ Messages.getString("VPNClient.title"), "popup-error", -1); //$NON-NLS-1$ } try { Thread.sleep(10000); } catch (InterruptedException e2) { } Agent.this.startShutdownProcedure(); } } } } public void stopThread() { running = false; interrupt(); } } }