#!/usr/bin/env python # This is simple stupid WWW server intended to serve VNC java applet. # It is made to be called by xinetd. # It handles both HTTP and HTTPS on the same port. If HTTPS is allowed, any HTTP requests is responded with redirect to HTTPS. import re import sys import socket import time from OpenSSL import SSL, crypto TLS_KEY = "/etc/vnc/tls.key" TLS_CERT = "/etc/vnc/tls.cert" JAR_FILE = "/usr/share/vnc/classes/VncViewer.jar" TIMEOUT = 10 WIDTH = int(sys.argv[1]) HEIGHT = int(sys.argv[2]) VNC_PORT = int(sys.argv[3]) USE_HTTPS = not (len(sys.argv) >= 5 and sys.argv[4] == "NoHTTPS") # Take the stdin as our input socket (given from xinetd) conn = sock = socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM) # If we are supposed to use HTTPS, load certificate and replace conn with SSL connection. if USE_HTTPS: cert = crypto.load_certificate(crypto.FILETYPE_PEM, open(TLS_CERT, 'r').read()) context = SSL.Context(SSL.SSLv23_METHOD) context.use_privatekey_file(TLS_KEY) context.use_certificate(cert) conn = SSL.Connection(context, sock) conn.set_accept_state() # Send normal response def send_response(connection, ctype, response): connection.sendall( "HTTP/1.0 200 OK\n" + "Content-Type: " + ctype + "\n" + "Content-Length: " + str(len(response)) + "\n" + "Connection: close\n" + "\n" + response ) # Send redirect def send_redirect(connection, ctype, response, location): connection.sendall( "HTTP/1.0 301 Moved Permanently\n" + "Location: " + location + "\n" + "Content-Type: " + ctype + "\n" + "Content-Length: " + str(len(response)) + "\n" + "Connection: close\n" + "\n" + response ) # Try to read and parse HTTP request try: start_time = time.time() buffer = '' while True: buffer += conn.recv(1024) if buffer.endswith("\r\n\r\n") or start_time + TIMEOUT < time.time(): break method, url = buffer.split(" ", 2)[0:2] if url == '/VncViewer.jar': with open(JAR_FILE, 'r') as file: send_response(conn, "application/octet-stream", file.read()) else: response = \ """ Remote Desktop """%(WIDTH, HEIGHT, VNC_PORT, 'X509None' if USE_HTTPS else 'TLSNone', cert.digest('SHA1') if USE_HTTPS else '') send_response(conn, "text/html", response) except SSL.Error: # If SSL failed, it is most probably because the browser is actually trying to do normal HTTP request. # We have now a partially consumed HTTP request in sock, let's try if we can get Host header out of it partial_request = sock.recv(8000) # Arbitrary big number, if the request is longer than this, we will just skip the rest. host = None match = re.search(r"\r\nHost: ([^\r]+)\r\n", partial_request) if match: host = match.group(1) if host: # If we got host header, we can redirect nicely with HTTP 301. send_redirect(sock, "text.html", "Use https.", "https://" + host) else: # If we don't know the host header, redirect using javascript. send_response(sock, "text.html", "Use https.")