SocketFactory.class HTTPConnectSocketFactory.class \
VNCProxyConnectSocketFactory.class VNCProxyConnectSocket.class \
HTTPConnectSocket.class ReloginPanel.class \
- InStream.class MemInStream.class ZlibInStream.class
+ InStream.class MemInStream.class ZlibInStream.class \
+ VNCProxyConnectSocketWrapper.class SocketWrapper.class SocketWrapper\$$WrappingSocketImpl.class SIPBTrustManager.class
SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \
VncCanvas2.java \
SocketFactory.java HTTPConnectSocketFactory.java \
VNCProxyConnectSocketFactory.java VNCProxyConnectSocket.java \
HTTPConnectSocket.java ReloginPanel.java \
- InStream.java MemInStream.java ZlibInStream.java
+ InStream.java MemInStream.java ZlibInStream.java \
+ VNCProxyConnectSocketWrapper.java SocketWrapper.java SIPBTrustManager.java
+
+EXTRAJAR = trust.store
all: $(CLASSES) $(ARCHIVE)
$(JC) $(JCFLAGS) -O $(SOURCES)
$(ARCHIVE): $(CLASSES) $(MANIFEST)
- $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES)
+ $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) $(EXTRAJAR)
install: $(CLASSES) $(ARCHIVE)
$(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR)
--- /dev/null
+/*
+ * Copyright 2006 Perry Nguyen <pfnguyen@hanhuy.com>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+public class SIPBTrustManager implements X509TrustManager {
+ private X509TrustManager trustManager;
+ private final static char[] KEY_STORE_PASSWORD =
+ { 'f', 'o', 'o', 'b', 'a', 'r' };
+ private final static String KEY_STORE_RESOURCE =
+ "trust.store";
+
+ private KeyStore loadKeyStore() throws Exception {
+ InputStream in = getClass().getClassLoader().getResourceAsStream(
+ KEY_STORE_RESOURCE);
+ KeyStore ks = null;
+ try {
+ if (in == null) {
+ //log.severe("Unable to open KeyStore");
+ throw new NullPointerException();
+ }
+ ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ ks.load(in, KEY_STORE_PASSWORD);
+ /*if (log.isLoggable(Level.FINEST)) {
+ for (Enumeration<String> aliases = ks.aliases();
+ aliases.hasMoreElements();) {
+ String alias = aliases.nextElement();
+ log.finest("ALIAS: " + alias);
+ }
+ }*/
+ } catch (NoSuchAlgorithmException e) {
+ throwError(e);
+ } catch (CertificateException e) {
+ throwError(e);
+ } catch (IOException e) {
+ throwError(e);
+ } catch (KeyStoreException e) {
+ throwError(e);
+ } finally {
+ try {
+ if (in != null)
+ in.close();
+ }
+ catch (IOException e) { } // ignore
+ }
+ return ks;
+ }
+ private void createTrustManager() {
+ try {
+ try {
+ KeyStore keystore = loadKeyStore();
+ TrustManagerFactory factory = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ factory.init(keystore);
+ TrustManager[] trustManagers = factory.getTrustManagers();
+ if (trustManagers.length == 0)
+ throw new IllegalStateException("No trust manager found");
+ setTrustManager((X509TrustManager) trustManagers[0]);
+ } catch (NoSuchAlgorithmException e) {
+ throwError(e);
+ } catch (KeyStoreException e) {
+ throwError(e);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ private void throwError(Exception e) throws Exception {
+ //HttpClientError error = new HttpClientError(e.getMessage());
+ //error.initCause(e);
+ throw e;
+ }
+ public X509TrustManager getTrustManager() {
+ if (trustManager == null)
+ createTrustManager();
+ return trustManager;
+ }
+
+ public void setTrustManager(X509TrustManager trustManager) {
+ this.trustManager = trustManager;
+ }
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ getTrustManager().checkClientTrusted(chain, authType);
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ getTrustManager().checkServerTrusted(chain, authType);
+
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return getTrustManager().getAcceptedIssuers();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Written by Dawid Kurzyniec and released to the public domain, as explained
+ * at http://creativecommons.org/licenses/publicdomain
+ */
+
+//package edu.emory.mathcs.util.net;
+
+import java.io.*;
+import java.net.*;
+import java.nio.channels.*;
+
+/**
+ * Wrapper for sockets which enables to add functionality in subclasses
+ * on top of existing, connected sockets. It is useful when direct subclassing
+ * of delegate socket class is not possible, e.g. if the delegate socket is
+ * created by a library. Possible usage example is socket factory chaining.
+ * This class delegates all socket-related requests to the wrapped delegate,
+ * as of JDK 1.4.
+ *
+ * @author Dawid Kurzyniec
+ * @version 1.4
+ */
+public abstract class SocketWrapper extends Socket {
+
+ /**
+ * the wrapped delegate socket.
+ */
+ protected final Socket delegate;
+
+ /**
+ * Creates new socket wrapper for a given socket. The delegate
+ * must be connected and bound and it must not be closed.
+ * @param delegate the delegate socket to wrap
+ * @throws SocketException if the delegate socket is closed, not bound,
+ * or not connected
+ */
+ protected SocketWrapper(Socket delegate) throws SocketException {
+ super(new WrappingSocketImpl(delegate));
+ this.delegate = delegate;
+ }
+
+ public SocketChannel getChannel() {
+ return delegate.getChannel();
+ }
+
+ /**
+ * Returns true, indicating that the socket is bound.
+ *
+ * @return true
+ */
+ public boolean isBound() {
+ return true;
+ }
+
+ public boolean isClosed() {
+ return super.isClosed() || delegate.isClosed();
+ }
+
+ /**
+ * Returns true, indicating that the socket is connected.
+ *
+ * @return true
+ */
+ public boolean isConnected() {
+ return true;
+ }
+
+ public boolean isInputShutdown() {
+ return super.isInputShutdown() || delegate.isInputShutdown();
+ }
+
+ public boolean isOutputShutdown() {
+ return super.isInputShutdown() || delegate.isOutputShutdown();
+ }
+
+ private static class WrappingSocketImpl extends SocketImpl {
+ private final Socket delegate;
+ WrappingSocketImpl(Socket delegate) throws SocketException {
+ if (delegate == null) {
+ throw new NullPointerException();
+ }
+ if (delegate.isClosed()) {
+ throw new SocketException("Delegate server socket is closed");
+ }
+ if (!(delegate.isBound())) {
+ throw new SocketException("Delegate server socket is not bound");
+ }
+ if (!(delegate.isConnected())) {
+ throw new SocketException("Delegate server socket is not connected");
+ }
+ this.delegate = delegate;
+ }
+
+ protected void create(boolean stream) {}
+
+ protected void connect(String host, int port) {
+ // delegate is always connected, thus this method is never called
+ throw new UnsupportedOperationException();
+ }
+
+ protected void connect(InetAddress address, int port) {
+ // delegate is always connected, thus this method is never called
+ throw new UnsupportedOperationException();
+ }
+
+ protected void connect(SocketAddress address, int timeout) {
+ // delegate is always connected, thus this method is never called
+ throw new UnsupportedOperationException();
+ }
+
+ protected void bind(InetAddress host, int port) {
+ // delegate is always bound, thus this method is never called
+ throw new UnsupportedOperationException();
+ }
+
+ protected void listen(int backlog) {
+ // this wrapper is never used by a ServerSocket
+ throw new UnsupportedOperationException();
+ }
+
+ protected void accept(SocketImpl s) {
+ // this wrapper is never used by a ServerSocket
+ throw new UnsupportedOperationException();
+ }
+
+ protected InputStream getInputStream() throws IOException {
+ return delegate.getInputStream();
+ }
+
+ protected OutputStream getOutputStream() throws IOException {
+ return delegate.getOutputStream();
+ }
+
+ protected int available() throws IOException {
+ return getInputStream().available();
+ }
+
+ protected void close() throws IOException {
+ delegate.close();
+ }
+
+ protected void shutdownInput() throws IOException {
+ delegate.shutdownInput();
+ }
+
+ protected void shutdownOutput() throws IOException {
+ delegate.shutdownOutput();
+ }
+
+ protected FileDescriptor getFileDescriptor() {
+ // this wrapper is never used by a ServerSocket
+ throw new UnsupportedOperationException();
+ }
+
+ protected InetAddress getInetAddress() {
+ return delegate.getInetAddress();
+ }
+
+ protected int getPort() {
+ return delegate.getPort();
+ }
+
+ protected boolean supportsUrgentData() {
+ return false; // must be overridden in sub-class
+ }
+
+ protected void sendUrgentData (int data) throws IOException {
+ delegate.sendUrgentData(data);
+ }
+
+ protected int getLocalPort() {
+ return delegate.getLocalPort();
+ }
+
+ public Object getOption(int optID) throws SocketException {
+ switch (optID) {
+ case SocketOptions.IP_TOS:
+ return new Integer(delegate.getTrafficClass());
+ case SocketOptions.SO_BINDADDR:
+ return delegate.getLocalAddress();
+ case SocketOptions.SO_KEEPALIVE:
+ return Boolean.valueOf(delegate.getKeepAlive());
+ case SocketOptions.SO_LINGER:
+ return new Integer(delegate.getSoLinger());
+ case SocketOptions.SO_OOBINLINE:
+ return Boolean.valueOf(delegate.getOOBInline());
+ case SocketOptions.SO_RCVBUF:
+ return new Integer(delegate.getReceiveBufferSize());
+ case SocketOptions.SO_REUSEADDR:
+ return Boolean.valueOf(delegate.getReuseAddress());
+ case SocketOptions.SO_SNDBUF:
+ return new Integer(delegate.getSendBufferSize());
+ case SocketOptions.SO_TIMEOUT:
+ return new Integer(delegate.getSoTimeout());
+ case SocketOptions.TCP_NODELAY:
+ return Boolean.valueOf(delegate.getTcpNoDelay());
+ case SocketOptions.SO_BROADCAST:
+ default:
+ throw new IllegalArgumentException("Unsupported option type");
+ }
+ }
+
+ public void setOption(int optID, Object value) throws SocketException {
+ switch (optID) {
+ case SocketOptions.SO_BINDADDR:
+ throw new IllegalArgumentException("Socket is bound");
+ case SocketOptions.SO_KEEPALIVE:
+ delegate.setKeepAlive(((Boolean)value).booleanValue());
+ break;
+ case SocketOptions.SO_LINGER:
+ if (value instanceof Boolean) {
+ delegate.setSoLinger(((Boolean)value).booleanValue(), 0);
+ }
+ else {
+ delegate.setSoLinger(true, ((Integer)value).intValue());
+ }
+ break;
+ case SocketOptions.SO_OOBINLINE:
+ delegate.setOOBInline(((Boolean)value).booleanValue());
+ break;
+ case SocketOptions.SO_RCVBUF:
+ delegate.setReceiveBufferSize(((Integer)value).intValue());
+ break;
+ case SocketOptions.SO_REUSEADDR:
+ delegate.setReuseAddress(((Boolean)value).booleanValue());
+ break;
+ case SocketOptions.SO_SNDBUF:
+ delegate.setSendBufferSize(((Integer)value).intValue());
+ break;
+ case SocketOptions.SO_TIMEOUT:
+ delegate.setSoTimeout(((Integer)value).intValue());
+ break;
+ case SocketOptions.TCP_NODELAY:
+ delegate.setTcpNoDelay(((Boolean)value).booleanValue());
+ break;
+ case SocketOptions.SO_BROADCAST:
+ default:
+ throw new IllegalArgumentException("Unsupported option type");
+ }
+ }
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof SocketWrapper)) return false;
+ SocketWrapper that = (SocketWrapper)obj;
+ return this.delegate.equals(that.delegate);
+ }
+
+ public int hashCode() {
+ return delegate.hashCode() ^ 0x01010101;
+ }
+}
\ No newline at end of file
import java.applet.*;
import java.net.*;
+import javax.net.ssl.*;
import java.io.*;
class VNCProxyConnectSocketFactory implements SocketFactory {
+ SSLSocketFactory factory;
+
+ public VNCProxyConnectSocketFactory() {
+ try {
+ SSLContext c = SSLContext.getInstance("SSL");
+ c.init(null,
+ new TrustManager[] { new SIPBTrustManager() },
+ null);
+ factory =
+ (SSLSocketFactory)c.getSocketFactory();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
public Socket createSocket(String host, int port, Applet applet)
throws IOException {
System.out.println("VNCProxy CONNECT via proxy " + host +
" port " + port + " to vm " + vmname);
- VNCProxyConnectSocket s =
- new VNCProxyConnectSocket(host, port, vmname, authtoken);
+ SSLSocket ssls = (SSLSocket)factory.createSocket(host, port);
+ ssls.startHandshake();
+ VNCProxyConnectSocketWrapper s =
+ new VNCProxyConnectSocketWrapper(ssls, vmname, authtoken);
return (Socket)s;
}
--- /dev/null
+//
+// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved.
+// Copyright 2007 MIT Student Information Processing Board
+//
+// This 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 software 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 software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// VNCProxySocket.java together with VNCProxySocketFactory.java
+// implement an alternate way to connect to VNC servers via one or two
+// VNCProxy proxies supporting the VNCProxy VNCCONNECT method.
+//
+
+import java.net.*;
+import java.io.*;
+
+class VNCProxyConnectSocketWrapper extends SocketWrapper {
+
+ public VNCProxyConnectSocketWrapper(Socket sock,
+ String vmname, String authtoken)
+ throws IOException {
+
+ super(sock);
+
+ // Send the CONNECT request
+ getOutputStream().write(("CONNECTVNC " + vmname +
+ " VNCProxy/1.0\r\nAuth-token: " + authtoken +
+ "\r\n\r\n").getBytes());
+
+ // Read the first line of the response
+ DataInputStream is = new DataInputStream(getInputStream());
+ String str = is.readLine();
+
+ // Check the HTTP error code -- it should be "200" on success
+ if (!str.startsWith("VNCProxy/1.0 200 ")) {
+ if (str.startsWith("VNCProxy/1.0 "))
+ str = str.substring(13);
+ throw new IOException("Proxy reports \"" + str + "\"");
+ }
+
+ // Success -- skip remaining HTTP headers
+ do {
+ str = is.readLine();
+ } while (str.length() != 0);
+ }
+}
+