package de.bwlehrpool.bwlp_guac; import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class VncConnection implements Closeable { private static final Logger LOGGER = LoggerFactory.getLogger(VncConnection.class); private final Socket sock; private final DataOutputStream out; private final DataInputStream in; public VncConnection(String host, int port) throws IOException { sock = new Socket(); sock.connect(new InetSocketAddress(host, port), 1200); sock.setSoTimeout(1000); out = new DataOutputStream(sock.getOutputStream()); in = new DataInputStream(sock.getInputStream()); } /** * @return Version string on success, null if not RFB * @throws IOException */ public String handshake() throws IOException { byte[] buffer = new byte[12]; in.readFully(buffer); if (buffer[0] != 'R' || buffer[1] != 'F' || buffer[2] != 'B') return null; out.write("RFB 003.008\n".getBytes()); out.flush(); return new String(buffer).substring(4, 11); } public boolean tryLogin(String passwd) throws IOException { if (passwd == null) return false; // Paswordless not supported yet (although simpler..) int numTypes = in.read(); if (numTypes == 0) { LOGGER.info("VNC Server @ " + sock.getRemoteSocketAddress() + " does not support any auth methods"); printError(); return false; } boolean ok = false; for (int i = 0; i < numTypes; ++i) { if (in.read() == 2) { ok = true; break; // Found "VNC Authentication" } } if (!ok) { LOGGER.info("VNC Server @ " + sock.getRemoteSocketAddress() + " does not support VNC Authentication"); return false; } out.write(2); // Pick passwd auth // Get challenge data byte[] challenge = new byte[16]; int ret = in.read(challenge); if (ret != 16) { LOGGER.info("Didn't receive challenge from VNC server @ " + sock.getRemoteSocketAddress()); return false; } // pad pw to 8 bytes byte[] pw_bytes = passwd.getBytes(); pw_bytes = Arrays.copyOf(pw_bytes, 8); // Encrypt out.write(WeakCrypto.vncEncrypt(pw_bytes, challenge)); // check reply int securityReply = in.readInt(); if (securityReply != 0) { LOGGER.info("Security reply = " + securityReply + " for VNC server @ " + sock.getRemoteSocketAddress()); return false; } return true; } private void printError() { try { int len = in.readInt(); byte[] msg = new byte[len]; in.readFully(msg); LOGGER.info(new String(msg, StandardCharsets.ISO_8859_1)); } catch (IOException e) { // Nothing, we're already kinda handling an error, so if we can't fetch the // message, ignore } } @Override public void close() throws IOException { try { in.close(); } catch (Exception e) { } try { out.close(); } catch (Exception e) { } try { sock.close(); } catch (Exception e) { } } }