File vnc_inetd_httpd of Package tigervnc.openSUSE_Leap_42.2_Update

#!/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 = \
    """<html>
        <head>
          <title>Remote Desktop</title>
        </head>
        <body>
          <embed type="application/x-java-applet;version=1.6" code="com.tigervnc.vncviewer.VncViewer" archive="VncViewer.jar" width="%d" height="%d"
            Port="%d"
            Embed="true"
            AlwaysShowServerDialog="false"
            SecurityTypes="%s"
            x509autoaccept="%s"
          >
        </body>
      </html>
    """%(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", "<html><body>Use https.</body></html>", "https://" + host)
  else:
    # If we don't know the host header, redirect using javascript.
    send_response(sock, "text.html", "<html><head><script>document.location.protocol = 'https';</script></head><body>Use https.</body></html>")
openSUSE Build Service is sponsored by