Blame qemu-sasl-05-vnc-tls-vencrypt.patch

Daniel P. Berrange 42af21
This patch refactors the existing TLS code to make the main VNC code
Daniel P. Berrange 42af21
more managable. The code moves to two new files
Daniel P. Berrange 42af21
Daniel P. Berrange 42af21
 - vnc-tls.c: generic helpers for TLS handshake & credential setup
Daniel P. Berrange 42af21
 - vnc-auth-vencrypt.c: the actual VNC TLS authentication mechanism.
Daniel P. Berrange 42af21
Daniel P. Berrange 42af21
The reason for this split is that there are other TLS based auth
Daniel P. Berrange 42af21
mechanisms which we may like to use in the future. These can all
Daniel P. Berrange 42af21
share the same vnc-tls.c routines. In addition this will facilitate
Daniel P. Berrange 42af21
anyone who may want to port the vnc-tls.c file to allow for choice
Daniel P. Berrange 42af21
of GNUTLS & NSS for impl.
Daniel P. Berrange 42af21
Daniel P. Berrange 42af21
The TLS state is moved out of the VncState struct, and into a separate
Daniel P. Berrange 42af21
VncStateTLS struct, defined in vnc-tls.h. This is then referenced from
Daniel P. Berrange 42af21
the main VncState. End size of the struct is the same, but it keeps
Daniel P. Berrange 42af21
things a little more managable.
Daniel P. Berrange 42af21
Daniel P. Berrange 42af21
The vnc.h file gains a bunch more function prototypes, for functions
Daniel P. Berrange 42af21
in vnc.c that were previously static, but now need to be accessed
Daniel P. Berrange 42af21
from the separate auth code files.
Daniel P. Berrange 42af21
Daniel P. Berrange 42af21
The only TLS related code still in the main vl.c is the command line
Daniel P. Berrange 42af21
argument handling / setup, and the low level I/O routines calling
Daniel P. Berrange 42af21
gnutls_send/recv.
Daniel P. Berrange 42af21
Daniel P. Berrange 42af21
Daniel P. Berrange 42af21
 Makefile              |   11 
Daniel P. Berrange 42af21
 b/vnc-auth-vencrypt.c |  167 ++++++++++++++
Daniel P. Berrange 42af21
 b/vnc-auth-vencrypt.h |   33 ++
Daniel P. Berrange 42af21
 b/vnc-tls.c           |  414 +++++++++++++++++++++++++++++++++++
Daniel P. Berrange 42af21
 b/vnc-tls.h           |   70 ++++++
Daniel P. Berrange 42af21
 vnc.c                 |  581 +++-----------------------------------------------
Daniel P. Berrange 42af21
 vnc.h                 |   76 ++++--
Daniel P. Berrange 42af21
 7 files changed, 780 insertions(+), 572 deletions(-)
Daniel P. Berrange 42af21
Daniel P. Berrange 42af21
   Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Daniel P. Berrange 42af21
Glauber Costa 8571d0
Index: kvm-84.git-snapshot-20090303/qemu/Makefile
Glauber Costa 8571d0
===================================================================
Glauber Costa 8571d0
--- kvm-84.git-snapshot-20090303.orig/qemu/Makefile
Glauber Costa 8571d0
+++ kvm-84.git-snapshot-20090303/qemu/Makefile
Glauber Costa 8571d0
@@ -149,6 +149,9 @@ ifdef CONFIG_CURSES
Daniel P. Berrange 42af21
 OBJS+=curses.o
Daniel P. Berrange 42af21
 endif
Daniel P. Berrange 42af21
 OBJS+=vnc.o d3des.o
Daniel P. Berrange 42af21
+ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
+OBJS+=vnc-tls.o vnc-auth-vencrypt.o
Daniel P. Berrange 42af21
+endif
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 ifdef CONFIG_COCOA
Daniel P. Berrange 42af21
 OBJS+=cocoa.o
Glauber Costa 8571d0
@@ -172,10 +175,16 @@ sdl.o: sdl.c keymaps.h sdl_keysym.h
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS)
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-vnc.o: vnc.c keymaps.h sdl_keysym.h vnchextile.h d3des.c d3des.h
Daniel P. Berrange 42af21
+vnc.h: vnc-tls.h vnc-auth-vencrypt.h keymaps.h
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 vnc.o: CFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
+vnc-tls.o: vnc-tls.c vnc.h
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+vnc-auth-vencrypt.o: vnc-auth-vencrypt.c vnc.h
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
 curses.o: curses.c keymaps.h curses_keys.h
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 bt-host.o: CFLAGS += $(CONFIG_BLUEZ_CFLAGS)
Glauber Costa 8571d0
Index: kvm-84.git-snapshot-20090303/qemu/vnc-auth-vencrypt.c
Glauber Costa 8571d0
===================================================================
Glauber Costa 8571d0
--- /dev/null
Glauber Costa 8571d0
+++ kvm-84.git-snapshot-20090303/qemu/vnc-auth-vencrypt.c
Daniel P. Berrange 42af21
@@ -0,0 +1,167 @@
Daniel P. Berrange 42af21
+/*
Daniel P. Berrange 42af21
+ * QEMU VNC display driver: VeNCrypt authentication setup
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
Daniel P. Berrange 42af21
+ * Copyright (C) 2006 Fabrice Bellard
Daniel P. Berrange 42af21
+ * Copyright (C) 2009 Red Hat, Inc
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Daniel P. Berrange 42af21
+ * of this software and associated documentation files (the "Software"), to deal
Daniel P. Berrange 42af21
+ * in the Software without restriction, including without limitation the rights
Daniel P. Berrange 42af21
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Daniel P. Berrange 42af21
+ * copies of the Software, and to permit persons to whom the Software is
Daniel P. Berrange 42af21
+ * furnished to do so, subject to the following conditions:
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * The above copyright notice and this permission notice shall be included in
Daniel P. Berrange 42af21
+ * all copies or substantial portions of the Software.
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Daniel P. Berrange 42af21
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Daniel P. Berrange 42af21
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Daniel P. Berrange 42af21
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Daniel P. Berrange 42af21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Daniel P. Berrange 42af21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Daniel P. Berrange 42af21
+ * THE SOFTWARE.
Daniel P. Berrange 42af21
+ */
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#include "vnc.h"
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static void start_auth_vencrypt_subauth(VncState *vs)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    switch (vs->vd->subauth) {
Daniel P. Berrange 42af21
+    case VNC_AUTH_VENCRYPT_TLSNONE:
Daniel P. Berrange 42af21
+    case VNC_AUTH_VENCRYPT_X509NONE:
Daniel P. Berrange 42af21
+       VNC_DEBUG("Accept TLS auth none\n");
Daniel P. Berrange 42af21
+       vnc_write_u32(vs, 0); /* Accept auth completion */
Daniel P. Berrange 42af21
+       start_client_init(vs);
Daniel P. Berrange 42af21
+       break;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    case VNC_AUTH_VENCRYPT_TLSVNC:
Daniel P. Berrange 42af21
+    case VNC_AUTH_VENCRYPT_X509VNC:
Daniel P. Berrange 42af21
+       VNC_DEBUG("Start TLS auth VNC\n");
Daniel P. Berrange 42af21
+       start_auth_vnc(vs);
Daniel P. Berrange 42af21
+       break;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    default: /* Should not be possible, but just in case */
Daniel P. Berrange 42af21
+       VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
Daniel P. Berrange 42af21
+       vnc_write_u8(vs, 1);
Daniel P. Berrange 42af21
+       if (vs->minor >= 8) {
Daniel P. Berrange 42af21
+           static const char err[] = "Unsupported authentication type";
Daniel P. Berrange 42af21
+           vnc_write_u32(vs, sizeof(err));
Daniel P. Berrange 42af21
+           vnc_write(vs, err, sizeof(err));
Daniel P. Berrange 42af21
+       }
Daniel P. Berrange 42af21
+       vnc_client_error(vs);
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static void vnc_tls_handshake_io(void *opaque);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static int vnc_start_vencrypt_handshake(struct VncState *vs) {
Daniel P. Berrange 42af21
+    int ret;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if ((ret = gnutls_handshake(vs->tls.session)) < 0) {
Daniel P. Berrange 42af21
+       if (!gnutls_error_is_fatal(ret)) {
Daniel P. Berrange 42af21
+           VNC_DEBUG("Handshake interrupted (blocking)\n");
Daniel P. Berrange 42af21
+           if (!gnutls_record_get_direction(vs->tls.session))
Daniel P. Berrange 42af21
+               qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
Daniel P. Berrange 42af21
+           else
Daniel P. Berrange 42af21
+               qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
Daniel P. Berrange 42af21
+           return 0;
Daniel P. Berrange 42af21
+       }
Daniel P. Berrange 42af21
+       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
+       vnc_client_error(vs);
Daniel P. Berrange 42af21
+       return -1;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if (vs->vd->tls.x509verify) {
Daniel P. Berrange 42af21
+	if (vnc_tls_validate_certificate(vs) < 0) {
Daniel P. Berrange 42af21
+	    VNC_DEBUG("Client verification failed\n");
Daniel P. Berrange 42af21
+	    vnc_client_error(vs);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	} else {
Daniel P. Berrange 42af21
+	    VNC_DEBUG("Client verification passed\n");
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
Daniel P. Berrange 42af21
+    vs->tls.wiremode = VNC_WIREMODE_TLS;
Daniel P. Berrange 42af21
+    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    start_auth_vencrypt_subauth(vs);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    return 0;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static void vnc_tls_handshake_io(void *opaque) {
Daniel P. Berrange 42af21
+    struct VncState *vs = (struct VncState *)opaque;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    VNC_DEBUG("Handshake IO continue\n");
Daniel P. Berrange 42af21
+    vnc_start_vencrypt_handshake(vs);
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#define NEED_X509_AUTH(vs)			      \
Daniel P. Berrange 42af21
+    ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
Daniel P. Berrange 42af21
+     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
Daniel P. Berrange 42af21
+     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    int auth = read_u32(data, 0);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if (auth != vs->vd->subauth) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Rejecting auth %d\n", auth);
Daniel P. Berrange 42af21
+	vnc_write_u8(vs, 0); /* Reject auth */
Daniel P. Berrange 42af21
+	vnc_flush(vs);
Daniel P. Berrange 42af21
+	vnc_client_error(vs);
Daniel P. Berrange 42af21
+    } else {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
Daniel P. Berrange 42af21
+	vnc_write_u8(vs, 1); /* Accept auth */
Daniel P. Berrange 42af21
+	vnc_flush(vs);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) {
Daniel P. Berrange 42af21
+	    VNC_DEBUG("Failed to setup TLS\n");
Daniel P. Berrange 42af21
+	    return 0;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
Daniel P. Berrange 42af21
+	if (vnc_start_vencrypt_handshake(vs) < 0) {
Daniel P. Berrange 42af21
+	    VNC_DEBUG("Failed to start TLS handshake\n");
Daniel P. Berrange 42af21
+	    return 0;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    return 0;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    if (data[0] != 0 ||
Daniel P. Berrange 42af21
+	data[1] != 2) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
Daniel P. Berrange 42af21
+	vnc_write_u8(vs, 1); /* Reject version */
Daniel P. Berrange 42af21
+	vnc_flush(vs);
Daniel P. Berrange 42af21
+	vnc_client_error(vs);
Daniel P. Berrange 42af21
+    } else {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
Daniel P. Berrange 42af21
+	vnc_write_u8(vs, 0); /* Accept version */
Daniel P. Berrange 42af21
+	vnc_write_u8(vs, 1); /* Number of sub-auths */
Daniel P. Berrange 42af21
+	vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
Daniel P. Berrange 42af21
+	vnc_flush(vs);
Daniel P. Berrange 42af21
+	vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    return 0;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+void start_auth_vencrypt(VncState *vs)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    /* Send VeNCrypt version 0.2 */
Daniel P. Berrange 42af21
+    vnc_write_u8(vs, 0);
Daniel P. Berrange 42af21
+    vnc_write_u8(vs, 2);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Glauber Costa 8571d0
Index: kvm-84.git-snapshot-20090303/qemu/vnc-auth-vencrypt.h
Glauber Costa 8571d0
===================================================================
Glauber Costa 8571d0
--- /dev/null
Glauber Costa 8571d0
+++ kvm-84.git-snapshot-20090303/qemu/vnc-auth-vencrypt.h
Daniel P. Berrange 42af21
@@ -0,0 +1,33 @@
Daniel P. Berrange 42af21
+/*
Daniel P. Berrange 42af21
+ * QEMU VNC display driver
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
Daniel P. Berrange 42af21
+ * Copyright (C) 2006 Fabrice Bellard
Daniel P. Berrange 42af21
+ * Copyright (C) 2009 Red Hat, Inc
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Daniel P. Berrange 42af21
+ * of this software and associated documentation files (the "Software"), to deal
Daniel P. Berrange 42af21
+ * in the Software without restriction, including without limitation the rights
Daniel P. Berrange 42af21
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Daniel P. Berrange 42af21
+ * copies of the Software, and to permit persons to whom the Software is
Daniel P. Berrange 42af21
+ * furnished to do so, subject to the following conditions:
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * The above copyright notice and this permission notice shall be included in
Daniel P. Berrange 42af21
+ * all copies or substantial portions of the Software.
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Daniel P. Berrange 42af21
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Daniel P. Berrange 42af21
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Daniel P. Berrange 42af21
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Daniel P. Berrange 42af21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Daniel P. Berrange 42af21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Daniel P. Berrange 42af21
+ * THE SOFTWARE.
Daniel P. Berrange 42af21
+ */
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#ifndef __QEMU_VNC_AUTH_VENCRYPT_H__
Daniel P. Berrange 42af21
+#define __QEMU_VNC_AUTH_VENCRYPT_H__
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+void start_auth_vencrypt(VncState *vs);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#endif /* __QEMU_VNC_AUTH_VENCRYPT_H__ */
Glauber Costa 8571d0
Index: kvm-84.git-snapshot-20090303/qemu/vnc-tls.c
Glauber Costa 8571d0
===================================================================
Glauber Costa 8571d0
--- /dev/null
Glauber Costa 8571d0
+++ kvm-84.git-snapshot-20090303/qemu/vnc-tls.c
Daniel P. Berrange 42af21
@@ -0,0 +1,414 @@
Daniel P. Berrange 42af21
+/*
Daniel P. Berrange 42af21
+ * QEMU VNC display driver: TLS helpers
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
Daniel P. Berrange 42af21
+ * Copyright (C) 2006 Fabrice Bellard
Daniel P. Berrange 42af21
+ * Copyright (C) 2009 Red Hat, Inc
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Daniel P. Berrange 42af21
+ * of this software and associated documentation files (the "Software"), to deal
Daniel P. Berrange 42af21
+ * in the Software without restriction, including without limitation the rights
Daniel P. Berrange 42af21
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Daniel P. Berrange 42af21
+ * copies of the Software, and to permit persons to whom the Software is
Daniel P. Berrange 42af21
+ * furnished to do so, subject to the following conditions:
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * The above copyright notice and this permission notice shall be included in
Daniel P. Berrange 42af21
+ * all copies or substantial portions of the Software.
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Daniel P. Berrange 42af21
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Daniel P. Berrange 42af21
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Daniel P. Berrange 42af21
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Daniel P. Berrange 42af21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Daniel P. Berrange 42af21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Daniel P. Berrange 42af21
+ * THE SOFTWARE.
Daniel P. Berrange 42af21
+ */
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#include "vnc.h"
Daniel P. Berrange 42af21
+#include "qemu_socket.h"
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
Daniel P. Berrange 42af21
+/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
Daniel P. Berrange 42af21
+static void vnc_debug_gnutls_log(int level, const char* str) {
Daniel P. Berrange 42af21
+    VNC_DEBUG("%d %s", level, str);
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+#endif /* defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 */
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#define DH_BITS 1024
Daniel P. Berrange 42af21
+static gnutls_dh_params_t dh_params;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static int vnc_tls_initialize(void)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    static int tlsinitialized = 0;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if (tlsinitialized)
Daniel P. Berrange 42af21
+	return 1;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if (gnutls_global_init () < 0)
Daniel P. Berrange 42af21
+	return 0;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    /* XXX ought to re-generate diffie-hellmen params periodically */
Daniel P. Berrange 42af21
+    if (gnutls_dh_params_init (&dh_params) < 0)
Daniel P. Berrange 42af21
+	return 0;
Daniel P. Berrange 42af21
+    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
Daniel P. Berrange 42af21
+	return 0;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
Daniel P. Berrange 42af21
+    gnutls_global_set_log_level(10);
Daniel P. Berrange 42af21
+    gnutls_global_set_log_function(vnc_debug_gnutls_log);
Daniel P. Berrange 42af21
+#endif
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    tlsinitialized = 1;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    return 1;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
Daniel P. Berrange 42af21
+			    const void *data,
Daniel P. Berrange 42af21
+			    size_t len) {
Daniel P. Berrange 42af21
+    struct VncState *vs = (struct VncState *)transport;
Daniel P. Berrange 42af21
+    int ret;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+ retry:
Daniel P. Berrange 42af21
+    ret = send(vs->csock, data, len, 0);
Daniel P. Berrange 42af21
+    if (ret < 0) {
Daniel P. Berrange 42af21
+	if (errno == EINTR)
Daniel P. Berrange 42af21
+	    goto retry;
Daniel P. Berrange 42af21
+	return -1;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    return ret;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
Daniel P. Berrange 42af21
+			    void *data,
Daniel P. Berrange 42af21
+			    size_t len) {
Daniel P. Berrange 42af21
+    struct VncState *vs = (struct VncState *)transport;
Daniel P. Berrange 42af21
+    int ret;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+ retry:
Daniel P. Berrange 42af21
+    ret = recv(vs->csock, data, len, 0);
Daniel P. Berrange 42af21
+    if (ret < 0) {
Daniel P. Berrange 42af21
+	if (errno == EINTR)
Daniel P. Berrange 42af21
+	    goto retry;
Daniel P. Berrange 42af21
+	return -1;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    return ret;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    gnutls_anon_server_credentials anon_cred;
Daniel P. Berrange 42af21
+    int ret;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
+	return NULL;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    return anon_cred;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncDisplay *vd)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    gnutls_certificate_credentials_t x509_cred;
Daniel P. Berrange 42af21
+    int ret;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if (!vd->tls.x509cacert) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("No CA x509 certificate specified\n");
Daniel P. Berrange 42af21
+	return NULL;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    if (!vd->tls.x509cert) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("No server x509 certificate specified\n");
Daniel P. Berrange 42af21
+	return NULL;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    if (!vd->tls.x509key) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("No server private key specified\n");
Daniel P. Berrange 42af21
+	return NULL;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
+	return NULL;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
Daniel P. Berrange 42af21
+						      vd->tls.x509cacert,
Daniel P. Berrange 42af21
+						      GNUTLS_X509_FMT_PEM)) < 0) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
+	gnutls_certificate_free_credentials(x509_cred);
Daniel P. Berrange 42af21
+	return NULL;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
Daniel P. Berrange 42af21
+						     vd->tls.x509cert,
Daniel P. Berrange 42af21
+						     vd->tls.x509key,
Daniel P. Berrange 42af21
+						     GNUTLS_X509_FMT_PEM)) < 0) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
+	gnutls_certificate_free_credentials(x509_cred);
Daniel P. Berrange 42af21
+	return NULL;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if (vd->tls.x509cacrl) {
Daniel P. Berrange 42af21
+	if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
Daniel P. Berrange 42af21
+							vd->tls.x509cacrl,
Daniel P. Berrange 42af21
+							GNUTLS_X509_FMT_PEM)) < 0) {
Daniel P. Berrange 42af21
+	    VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
+	    gnutls_certificate_free_credentials(x509_cred);
Daniel P. Berrange 42af21
+	    return NULL;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    gnutls_certificate_set_dh_params (x509_cred, dh_params);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    return x509_cred;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+int vnc_tls_validate_certificate(struct VncState *vs)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    int ret;
Daniel P. Berrange 42af21
+    unsigned int status;
Daniel P. Berrange 42af21
+    const gnutls_datum_t *certs;
Daniel P. Berrange 42af21
+    unsigned int nCerts, i;
Daniel P. Berrange 42af21
+    time_t now;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    VNC_DEBUG("Validating client certificate\n");
Daniel P. Berrange 42af21
+    if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
+	return -1;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if ((now = time(NULL)) == ((time_t)-1)) {
Daniel P. Berrange 42af21
+	return -1;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if (status != 0) {
Daniel P. Berrange 42af21
+	if (status & GNUTLS_CERT_INVALID)
Daniel P. Berrange 42af21
+	    VNC_DEBUG("The certificate is not trusted.\n");
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
Daniel P. Berrange 42af21
+	    VNC_DEBUG("The certificate hasn't got a known issuer.\n");
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (status & GNUTLS_CERT_REVOKED)
Daniel P. Berrange 42af21
+	    VNC_DEBUG("The certificate has been revoked.\n");
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
Daniel P. Berrange 42af21
+	    VNC_DEBUG("The certificate uses an insecure algorithm\n");
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	return -1;
Daniel P. Berrange 42af21
+    } else {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Certificate is valid!\n");
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    /* Only support x509 for now */
Daniel P. Berrange 42af21
+    if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509)
Daniel P. Berrange 42af21
+	return -1;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts)))
Daniel P. Berrange 42af21
+	return -1;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    for (i = 0 ; i < nCerts ; i++) {
Daniel P. Berrange 42af21
+	gnutls_x509_crt_t cert;
Daniel P. Berrange 42af21
+	VNC_DEBUG ("Checking certificate chain %d\n", i);
Daniel P. Berrange 42af21
+	if (gnutls_x509_crt_init (&cert) < 0)
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
Daniel P. Berrange 42af21
+	    gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (gnutls_x509_crt_get_expiration_time (cert) < now) {
Daniel P. Berrange 42af21
+	    VNC_DEBUG("The certificate has expired\n");
Daniel P. Berrange 42af21
+	    gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (gnutls_x509_crt_get_activation_time (cert) > now) {
Daniel P. Berrange 42af21
+	    VNC_DEBUG("The certificate is not yet activated\n");
Daniel P. Berrange 42af21
+	    gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (gnutls_x509_crt_get_activation_time (cert) > now) {
Daniel P. Berrange 42af21
+	    VNC_DEBUG("The certificate is not yet activated\n");
Daniel P. Berrange 42af21
+	    gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    return 0;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+int vnc_tls_client_setup(struct VncState *vs,
Daniel P. Berrange 42af21
+			 int needX509Creds) {
Daniel P. Berrange 42af21
+    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
Daniel P. Berrange 42af21
+    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
Daniel P. Berrange 42af21
+    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
Daniel P. Berrange 42af21
+    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    VNC_DEBUG("Do TLS setup\n");
Daniel P. Berrange 42af21
+    if (vnc_tls_initialize() < 0) {
Daniel P. Berrange 42af21
+	VNC_DEBUG("Failed to init TLS\n");
Daniel P. Berrange 42af21
+	vnc_client_error(vs);
Daniel P. Berrange 42af21
+	return -1;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    if (vs->tls.session == NULL) {
Daniel P. Berrange 42af21
+	if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
Daniel P. Berrange 42af21
+	    vnc_client_error(vs);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (gnutls_set_default_priority(vs->tls.session) < 0) {
Daniel P. Berrange 42af21
+	    gnutls_deinit(vs->tls.session);
Daniel P. Berrange 42af21
+	    vs->tls.session = NULL;
Daniel P. Berrange 42af21
+	    vnc_client_error(vs);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
Daniel P. Berrange 42af21
+	    gnutls_deinit(vs->tls.session);
Daniel P. Berrange 42af21
+	    vs->tls.session = NULL;
Daniel P. Berrange 42af21
+	    vnc_client_error(vs);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
Daniel P. Berrange 42af21
+	    gnutls_deinit(vs->tls.session);
Daniel P. Berrange 42af21
+	    vs->tls.session = NULL;
Daniel P. Berrange 42af21
+	    vnc_client_error(vs);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
Daniel P. Berrange 42af21
+	    gnutls_deinit(vs->tls.session);
Daniel P. Berrange 42af21
+	    vs->tls.session = NULL;
Daniel P. Berrange 42af21
+	    vnc_client_error(vs);
Daniel P. Berrange 42af21
+	    return -1;
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	if (needX509Creds) {
Daniel P. Berrange 42af21
+	    gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
Daniel P. Berrange 42af21
+	    if (!x509_cred) {
Daniel P. Berrange 42af21
+		gnutls_deinit(vs->tls.session);
Daniel P. Berrange 42af21
+		vs->tls.session = NULL;
Daniel P. Berrange 42af21
+		vnc_client_error(vs);
Daniel P. Berrange 42af21
+		return -1;
Daniel P. Berrange 42af21
+	    }
Daniel P. Berrange 42af21
+	    if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
Daniel P. Berrange 42af21
+		gnutls_deinit(vs->tls.session);
Daniel P. Berrange 42af21
+		vs->tls.session = NULL;
Daniel P. Berrange 42af21
+		gnutls_certificate_free_credentials(x509_cred);
Daniel P. Berrange 42af21
+		vnc_client_error(vs);
Daniel P. Berrange 42af21
+		return -1;
Daniel P. Berrange 42af21
+	    }
Daniel P. Berrange 42af21
+	    if (vs->vd->tls.x509verify) {
Daniel P. Berrange 42af21
+		VNC_DEBUG("Requesting a client certificate\n");
Daniel P. Berrange 42af21
+		gnutls_certificate_server_set_request (vs->tls.session, GNUTLS_CERT_REQUEST);
Daniel P. Berrange 42af21
+	    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	} else {
Daniel P. Berrange 42af21
+	    gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
Daniel P. Berrange 42af21
+	    if (!anon_cred) {
Daniel P. Berrange 42af21
+		gnutls_deinit(vs->tls.session);
Daniel P. Berrange 42af21
+		vs->tls.session = NULL;
Daniel P. Berrange 42af21
+		vnc_client_error(vs);
Daniel P. Berrange 42af21
+		return -1;
Daniel P. Berrange 42af21
+	    }
Daniel P. Berrange 42af21
+	    if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_ANON, anon_cred) < 0) {
Daniel P. Berrange 42af21
+		gnutls_deinit(vs->tls.session);
Daniel P. Berrange 42af21
+		vs->tls.session = NULL;
Daniel P. Berrange 42af21
+		gnutls_anon_free_server_credentials(anon_cred);
Daniel P. Berrange 42af21
+		vnc_client_error(vs);
Daniel P. Berrange 42af21
+		return -1;
Daniel P. Berrange 42af21
+	    }
Daniel P. Berrange 42af21
+	}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+	gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs);
Daniel P. Berrange 42af21
+	gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
Daniel P. Berrange 42af21
+	gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    return 0;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+void vnc_tls_client_cleanup(struct VncState *vs)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    if (vs->tls.session) {
Daniel P. Berrange 42af21
+	gnutls_deinit(vs->tls.session);
Daniel P. Berrange 42af21
+	vs->tls.session = NULL;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+    vs->tls.wiremode = VNC_WIREMODE_CLEAR;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+static int vnc_set_x509_credential(VncDisplay *vd,
Daniel P. Berrange 42af21
+				   const char *certdir,
Daniel P. Berrange 42af21
+				   const char *filename,
Daniel P. Berrange 42af21
+				   char **cred,
Daniel P. Berrange 42af21
+				   int ignoreMissing)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    struct stat sb;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    if (*cred) {
Daniel P. Berrange 42af21
+	qemu_free(*cred);
Daniel P. Berrange 42af21
+	*cred = NULL;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    strcpy(*cred, certdir);
Daniel P. Berrange 42af21
+    strcat(*cred, "/");
Daniel P. Berrange 42af21
+    strcat(*cred, filename);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    VNC_DEBUG("Check %s\n", *cred);
Daniel P. Berrange 42af21
+    if (stat(*cred, &sb) < 0) {
Daniel P. Berrange 42af21
+	qemu_free(*cred);
Daniel P. Berrange 42af21
+	*cred = NULL;
Daniel P. Berrange 42af21
+	if (ignoreMissing && errno == ENOENT)
Daniel P. Berrange 42af21
+	    return 0;
Daniel P. Berrange 42af21
+	return -1;
Daniel P. Berrange 42af21
+    }
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    return 0;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#define X509_CA_CERT_FILE "ca-cert.pem"
Daniel P. Berrange 42af21
+#define X509_CA_CRL_FILE "ca-crl.pem"
Daniel P. Berrange 42af21
+#define X509_SERVER_KEY_FILE "server-key.pem"
Daniel P. Berrange 42af21
+#define X509_SERVER_CERT_FILE "server-cert.pem"
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
Daniel P. Berrange 42af21
+			       const char *certdir)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    if (vnc_set_x509_credential(vd, certdir, X509_CA_CERT_FILE, &vd->tls.x509cacert, 0) < 0)
Daniel P. Berrange 42af21
+	goto cleanup;
Daniel P. Berrange 42af21
+    if (vnc_set_x509_credential(vd, certdir, X509_CA_CRL_FILE, &vd->tls.x509cacrl, 1) < 0)
Daniel P. Berrange 42af21
+	goto cleanup;
Daniel P. Berrange 42af21
+    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_CERT_FILE, &vd->tls.x509cert, 0) < 0)
Daniel P. Berrange 42af21
+	goto cleanup;
Daniel P. Berrange 42af21
+    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_KEY_FILE, &vd->tls.x509key, 0) < 0)
Daniel P. Berrange 42af21
+	goto cleanup;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    return 0;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+ cleanup:
Daniel P. Berrange 42af21
+    qemu_free(vd->tls.x509cacert);
Daniel P. Berrange 42af21
+    qemu_free(vd->tls.x509cacrl);
Daniel P. Berrange 42af21
+    qemu_free(vd->tls.x509cert);
Daniel P. Berrange 42af21
+    qemu_free(vd->tls.x509key);
Daniel P. Berrange 42af21
+    vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
Daniel P. Berrange 42af21
+    return -1;
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Glauber Costa 8571d0
Index: kvm-84.git-snapshot-20090303/qemu/vnc-tls.h
Glauber Costa 8571d0
===================================================================
Glauber Costa 8571d0
--- /dev/null
Glauber Costa 8571d0
+++ kvm-84.git-snapshot-20090303/qemu/vnc-tls.h
Daniel P. Berrange 42af21
@@ -0,0 +1,70 @@
Daniel P. Berrange 42af21
+/*
Daniel P. Berrange 42af21
+ * QEMU VNC display driver. TLS helpers
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
Daniel P. Berrange 42af21
+ * Copyright (C) 2006 Fabrice Bellard
Daniel P. Berrange 42af21
+ * Copyright (C) 2009 Red Hat, Inc
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Daniel P. Berrange 42af21
+ * of this software and associated documentation files (the "Software"), to deal
Daniel P. Berrange 42af21
+ * in the Software without restriction, including without limitation the rights
Daniel P. Berrange 42af21
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Daniel P. Berrange 42af21
+ * copies of the Software, and to permit persons to whom the Software is
Daniel P. Berrange 42af21
+ * furnished to do so, subject to the following conditions:
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * The above copyright notice and this permission notice shall be included in
Daniel P. Berrange 42af21
+ * all copies or substantial portions of the Software.
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Daniel P. Berrange 42af21
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Daniel P. Berrange 42af21
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Daniel P. Berrange 42af21
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Daniel P. Berrange 42af21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Daniel P. Berrange 42af21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Daniel P. Berrange 42af21
+ * THE SOFTWARE.
Daniel P. Berrange 42af21
+ */
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#ifndef __QEMU_VNC_TLS_H__
Daniel P. Berrange 42af21
+#define __QEMU_VNC_TLS_H__
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#include <gnutls/gnutls.h>
Daniel P. Berrange 42af21
+#include <gnutls/x509.h>
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+enum {
Daniel P. Berrange 42af21
+    VNC_WIREMODE_CLEAR,
Daniel P. Berrange 42af21
+    VNC_WIREMODE_TLS,
Daniel P. Berrange 42af21
+};
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+typedef struct VncDisplayTLS VncDisplayTLS;
Daniel P. Berrange 42af21
+typedef struct VncStateTLS VncStateTLS;
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+/* Server state */
Daniel P. Berrange 42af21
+struct VncDisplayTLS {
Daniel P. Berrange 42af21
+    int x509verify; /* Non-zero if server requests & validates client cert */
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+    /* Paths to x509 certs/keys */
Daniel P. Berrange 42af21
+    char *x509cacert;
Daniel P. Berrange 42af21
+    char *x509cacrl;
Daniel P. Berrange 42af21
+    char *x509cert;
Daniel P. Berrange 42af21
+    char *x509key;
Daniel P. Berrange 42af21
+};
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+/* Per client state */
Daniel P. Berrange 42af21
+struct VncStateTLS {
Daniel P. Berrange 42af21
+    /* Whether data is being TLS encrypted yet */
Daniel P. Berrange 42af21
+    int wiremode;
Daniel P. Berrange 42af21
+    gnutls_session_t session;
Daniel P. Berrange 42af21
+};
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+int vnc_tls_client_setup(VncState *vs, int x509Creds);
Daniel P. Berrange 42af21
+void vnc_tls_client_cleanup(VncState *vs);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+int vnc_tls_validate_certificate(VncState *vs);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
Daniel P. Berrange 42af21
+			       const char *path);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#endif /* __QEMU_VNC_TLS_H__ */
Daniel P. Berrange 42af21
+
Glauber Costa 8571d0
Index: kvm-84.git-snapshot-20090303/qemu/vnc.c
Glauber Costa 8571d0
===================================================================
Glauber Costa 8571d0
--- kvm-84.git-snapshot-20090303.orig/qemu/vnc.c
Glauber Costa 8571d0
+++ kvm-84.git-snapshot-20090303/qemu/vnc.c
Daniel P. Berrange 42af21
@@ -34,21 +34,6 @@
Daniel P. Berrange 42af21
 #include "vnc_keysym.h"
Daniel P. Berrange 42af21
 #include "d3des.h"
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-// #define _VNC_DEBUG 1
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-#ifdef _VNC_DEBUG
Daniel P. Berrange 42af21
-#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-#if defined(CONFIG_VNC_TLS) && _VNC_DEBUG >= 2
Daniel P. Berrange 42af21
-/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
Daniel P. Berrange 42af21
-static void vnc_debug_gnutls_log(int level, const char* str) {
Daniel P. Berrange 42af21
-    VNC_DEBUG("%d %s", level, str);
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
Daniel P. Berrange 42af21
-#else
Daniel P. Berrange 42af21
-#define VNC_DEBUG(fmt, ...) do { } while (0)
Daniel P. Berrange 42af21
-#endif
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
 #define count_bits(c, v) { \
Daniel P. Berrange 42af21
     for (c = 0; v; v >>= 1) \
Daniel P. Berrange 42af21
     { \
Daniel P. Berrange 42af21
@@ -204,14 +189,7 @@ static inline uint32_t vnc_has_feature(V
Daniel P. Berrange 42af21
    3) resolutions > 1024
Daniel P. Berrange 42af21
 */
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_write(VncState *vs, const void *data, size_t len);
Daniel P. Berrange 42af21
-static void vnc_write_u32(VncState *vs, uint32_t value);
Daniel P. Berrange 42af21
-static void vnc_write_s32(VncState *vs, int32_t value);
Daniel P. Berrange 42af21
-static void vnc_write_u16(VncState *vs, uint16_t value);
Daniel P. Berrange 42af21
-static void vnc_write_u8(VncState *vs, uint8_t value);
Daniel P. Berrange 42af21
-static void vnc_flush(VncState *vs);
Daniel P. Berrange 42af21
 static void vnc_update_client(void *opaque);
Daniel P. Berrange 42af21
-static void vnc_client_read(void *opaque);
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 static void vnc_colordepth(VncState *vs);
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
@@ -867,10 +845,7 @@ static int vnc_client_io_error(VncState 
Daniel P. Berrange 42af21
         if (vs->input.buffer) qemu_free(vs->input.buffer);
Daniel P. Berrange 42af21
         if (vs->output.buffer) qemu_free(vs->output.buffer);
Daniel P. Berrange 42af21
 #ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-	if (vs->tls_session) {
Daniel P. Berrange 42af21
-	    gnutls_deinit(vs->tls_session);
Daniel P. Berrange 42af21
-	    vs->tls_session = NULL;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
+	vnc_tls_client_cleanup(vs);
Daniel P. Berrange 42af21
 #endif /* CONFIG_VNC_TLS */
Daniel P. Berrange 42af21
         audio_del(vs);
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
@@ -896,19 +871,20 @@ static int vnc_client_io_error(VncState 
Daniel P. Berrange 42af21
     return ret;
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_client_error(VncState *vs)
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+void vnc_client_error(VncState *vs)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     vnc_client_io_error(vs, -1, EINVAL);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_client_write(void *opaque)
Daniel P. Berrange 42af21
+void vnc_client_write(void *opaque)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     long ret;
Daniel P. Berrange 42af21
     VncState *vs = opaque;
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 #ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-    if (vs->tls_session) {
Daniel P. Berrange 42af21
-	ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset);
Daniel P. Berrange 42af21
+    if (vs->tls.session) {
Daniel P. Berrange 42af21
+	ret = gnutls_write(vs->tls.session, vs->output.buffer, vs->output.offset);
Daniel P. Berrange 42af21
 	if (ret < 0) {
Daniel P. Berrange 42af21
 	    if (ret == GNUTLS_E_AGAIN)
Daniel P. Berrange 42af21
 		errno = EAGAIN;
Daniel P. Berrange 42af21
@@ -931,13 +907,13 @@ static void vnc_client_write(void *opaqu
Daniel P. Berrange 42af21
     }
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
Daniel P. Berrange 42af21
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     vs->read_handler = func;
Daniel P. Berrange 42af21
     vs->read_handler_expect = expecting;
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_client_read(void *opaque)
Daniel P. Berrange 42af21
+void vnc_client_read(void *opaque)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     VncState *vs = opaque;
Daniel P. Berrange 42af21
     long ret;
Daniel P. Berrange 42af21
@@ -945,8 +921,8 @@ static void vnc_client_read(void *opaque
Daniel P. Berrange 42af21
     buffer_reserve(&vs->input, 4096);
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 #ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-    if (vs->tls_session) {
Daniel P. Berrange 42af21
-	ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096);
Daniel P. Berrange 42af21
+    if (vs->tls.session) {
Daniel P. Berrange 42af21
+	ret = gnutls_read(vs->tls.session, buffer_end(&vs->input), 4096);
Daniel P. Berrange 42af21
 	if (ret < 0) {
Daniel P. Berrange 42af21
 	    if (ret == GNUTLS_E_AGAIN)
Daniel P. Berrange 42af21
 		errno = EAGAIN;
Daniel P. Berrange 42af21
@@ -980,7 +956,7 @@ static void vnc_client_read(void *opaque
Daniel P. Berrange 42af21
     }
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_write(VncState *vs, const void *data, size_t len)
Daniel P. Berrange 42af21
+void vnc_write(VncState *vs, const void *data, size_t len)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     buffer_reserve(&vs->output, len);
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
@@ -991,12 +967,12 @@ static void vnc_write(VncState *vs, cons
Daniel P. Berrange 42af21
     buffer_append(&vs->output, data, len);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_write_s32(VncState *vs, int32_t value)
Daniel P. Berrange 42af21
+void vnc_write_s32(VncState *vs, int32_t value)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     vnc_write_u32(vs, *(uint32_t *)&value);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_write_u32(VncState *vs, uint32_t value)
Daniel P. Berrange 42af21
+void vnc_write_u32(VncState *vs, uint32_t value)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     uint8_t buf[4];
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
@@ -1008,7 +984,7 @@ static void vnc_write_u32(VncState *vs, 
Daniel P. Berrange 42af21
     vnc_write(vs, buf, 4);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_write_u16(VncState *vs, uint16_t value)
Daniel P. Berrange 42af21
+void vnc_write_u16(VncState *vs, uint16_t value)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     uint8_t buf[2];
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
@@ -1018,74 +994,39 @@ static void vnc_write_u16(VncState *vs, 
Daniel P. Berrange 42af21
     vnc_write(vs, buf, 2);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_write_u8(VncState *vs, uint8_t value)
Daniel P. Berrange 42af21
+void vnc_write_u8(VncState *vs, uint8_t value)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     vnc_write(vs, (char *)&value, 1);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static void vnc_flush(VncState *vs)
Daniel P. Berrange 42af21
+void vnc_flush(VncState *vs)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     if (vs->output.offset)
Daniel P. Berrange 42af21
 	vnc_client_write(vs);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static uint8_t read_u8(uint8_t *data, size_t offset)
Daniel P. Berrange 42af21
+uint8_t read_u8(uint8_t *data, size_t offset)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     return data[offset];
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static uint16_t read_u16(uint8_t *data, size_t offset)
Daniel P. Berrange 42af21
+uint16_t read_u16(uint8_t *data, size_t offset)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static int32_t read_s32(uint8_t *data, size_t offset)
Daniel P. Berrange 42af21
+int32_t read_s32(uint8_t *data, size_t offset)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
Daniel P. Berrange 42af21
 		     (data[offset + 2] << 8) | data[offset + 3]);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static uint32_t read_u32(uint8_t *data, size_t offset)
Daniel P. Berrange 42af21
+uint32_t read_u32(uint8_t *data, size_t offset)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     return ((data[offset] << 24) | (data[offset + 1] << 16) |
Daniel P. Berrange 42af21
 	    (data[offset + 2] << 8) | data[offset + 3]);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-#ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
Daniel P. Berrange 42af21
-                            const void *data,
Daniel P. Berrange 42af21
-                            size_t len) {
Daniel P. Berrange 42af21
-    struct VncState *vs = (struct VncState *)transport;
Daniel P. Berrange 42af21
-    int ret;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
- retry:
Daniel P. Berrange 42af21
-    ret = send(vs->csock, data, len, 0);
Daniel P. Berrange 42af21
-    if (ret < 0) {
Daniel P. Berrange 42af21
-	if (errno == EINTR)
Daniel P. Berrange 42af21
-	    goto retry;
Daniel P. Berrange 42af21
-	return -1;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-    return ret;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
Daniel P. Berrange 42af21
-                            void *data,
Daniel P. Berrange 42af21
-                            size_t len) {
Daniel P. Berrange 42af21
-    struct VncState *vs = (struct VncState *)transport;
Daniel P. Berrange 42af21
-    int ret;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
- retry:
Daniel P. Berrange 42af21
-    ret = recv(vs->csock, data, len, 0);
Daniel P. Berrange 42af21
-    if (ret < 0) {
Daniel P. Berrange 42af21
-	if (errno == EINTR)
Daniel P. Berrange 42af21
-	    goto retry;
Daniel P. Berrange 42af21
-	return -1;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-    return ret;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-#endif /* CONFIG_VNC_TLS */
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
 static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
@@ -1668,6 +1609,11 @@ static int protocol_client_init(VncState
Daniel P. Berrange 42af21
     return 0;
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
+void start_client_init(VncState *vs)
Daniel P. Berrange 42af21
+{
Daniel P. Berrange 42af21
+    vnc_read_when(vs, protocol_client_init, 1);
Daniel P. Berrange 42af21
+}
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
 static void make_challenge(VncState *vs)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     int i;
Daniel P. Berrange 42af21
@@ -1723,12 +1669,12 @@ static int protocol_client_auth_vnc(VncS
Daniel P. Berrange 42af21
 	vnc_write_u32(vs, 0); /* Accept auth */
Daniel P. Berrange 42af21
 	vnc_flush(vs);
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-	vnc_read_when(vs, protocol_client_init, 1);
Daniel P. Berrange 42af21
+        start_client_init(vs);
Daniel P. Berrange 42af21
     }
Daniel P. Berrange 42af21
     return 0;
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-static int start_auth_vnc(VncState *vs)
Daniel P. Berrange 42af21
+void start_auth_vnc(VncState *vs)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     make_challenge(vs);
Daniel P. Berrange 42af21
     /* Send client a 'random' challenge */
Daniel P. Berrange 42af21
@@ -1736,411 +1682,9 @@ static int start_auth_vnc(VncState *vs)
Daniel P. Berrange 42af21
     vnc_flush(vs);
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
     vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
Daniel P. Berrange 42af21
-    return 0;
Glauber Costa 8571d0
-}
Glauber Costa 8571d0
-
Glauber Costa 8571d0
-
Daniel P. Berrange 42af21
-#ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-#define DH_BITS 1024
Daniel P. Berrange 42af21
-static gnutls_dh_params_t dh_params;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static int vnc_tls_initialize(void)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    static int tlsinitialized = 0;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if (tlsinitialized)
Daniel P. Berrange 42af21
-	return 1;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if (gnutls_global_init () < 0)
Daniel P. Berrange 42af21
-	return 0;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    /* XXX ought to re-generate diffie-hellmen params periodically */
Daniel P. Berrange 42af21
-    if (gnutls_dh_params_init (&dh_params) < 0)
Daniel P. Berrange 42af21
-	return 0;
Daniel P. Berrange 42af21
-    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
Daniel P. Berrange 42af21
-	return 0;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
Daniel P. Berrange 42af21
-    gnutls_global_set_log_level(10);
Daniel P. Berrange 42af21
-    gnutls_global_set_log_function(vnc_debug_gnutls_log);
Daniel P. Berrange 42af21
-#endif
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    tlsinitialized = 1;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    return 1;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    gnutls_anon_server_credentials anon_cred;
Daniel P. Berrange 42af21
-    int ret;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
-	return NULL;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    return anon_cred;
Glauber Costa 8571d0
 }
Glauber Costa 8571d0
 
Glauber Costa 8571d0
 
Daniel P. Berrange 42af21
-static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    gnutls_certificate_credentials_t x509_cred;
Daniel P. Berrange 42af21
-    int ret;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if (!vs->vd->x509cacert) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("No CA x509 certificate specified\n");
Daniel P. Berrange 42af21
-	return NULL;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-    if (!vs->vd->x509cert) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("No server x509 certificate specified\n");
Daniel P. Berrange 42af21
-	return NULL;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-    if (!vs->vd->x509key) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("No server private key specified\n");
Daniel P. Berrange 42af21
-	return NULL;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
-	return NULL;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
Daniel P. Berrange 42af21
-						      vs->vd->x509cacert,
Daniel P. Berrange 42af21
-						      GNUTLS_X509_FMT_PEM)) < 0) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
-	gnutls_certificate_free_credentials(x509_cred);
Daniel P. Berrange 42af21
-	return NULL;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
Daniel P. Berrange 42af21
-						     vs->vd->x509cert,
Daniel P. Berrange 42af21
-						     vs->vd->x509key,
Daniel P. Berrange 42af21
-						     GNUTLS_X509_FMT_PEM)) < 0) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
-	gnutls_certificate_free_credentials(x509_cred);
Daniel P. Berrange 42af21
-	return NULL;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if (vs->vd->x509cacrl) {
Daniel P. Berrange 42af21
-	if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
Daniel P. Berrange 42af21
-							vs->vd->x509cacrl,
Daniel P. Berrange 42af21
-							GNUTLS_X509_FMT_PEM)) < 0) {
Daniel P. Berrange 42af21
-	    VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
-	    gnutls_certificate_free_credentials(x509_cred);
Daniel P. Berrange 42af21
-	    return NULL;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    gnutls_certificate_set_dh_params (x509_cred, dh_params);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    return x509_cred;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static int vnc_validate_certificate(struct VncState *vs)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    int ret;
Daniel P. Berrange 42af21
-    unsigned int status;
Daniel P. Berrange 42af21
-    const gnutls_datum_t *certs;
Daniel P. Berrange 42af21
-    unsigned int nCerts, i;
Daniel P. Berrange 42af21
-    time_t now;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    VNC_DEBUG("Validating client certificate\n");
Daniel P. Berrange 42af21
-    if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
-	return -1;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if ((now = time(NULL)) == ((time_t)-1)) {
Daniel P. Berrange 42af21
-	return -1;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if (status != 0) {
Daniel P. Berrange 42af21
-	if (status & GNUTLS_CERT_INVALID)
Daniel P. Berrange 42af21
-	    VNC_DEBUG("The certificate is not trusted.\n");
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
Daniel P. Berrange 42af21
-	    VNC_DEBUG("The certificate hasn't got a known issuer.\n");
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (status & GNUTLS_CERT_REVOKED)
Daniel P. Berrange 42af21
-	    VNC_DEBUG("The certificate has been revoked.\n");
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
Daniel P. Berrange 42af21
-	    VNC_DEBUG("The certificate uses an insecure algorithm\n");
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	return -1;
Daniel P. Berrange 42af21
-    } else {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Certificate is valid!\n");
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    /* Only support x509 for now */
Daniel P. Berrange 42af21
-    if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509)
Daniel P. Berrange 42af21
-	return -1;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts)))
Daniel P. Berrange 42af21
-	return -1;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    for (i = 0 ; i < nCerts ; i++) {
Daniel P. Berrange 42af21
-	gnutls_x509_crt_t cert;
Daniel P. Berrange 42af21
-	VNC_DEBUG ("Checking certificate chain %d\n", i);
Daniel P. Berrange 42af21
-	if (gnutls_x509_crt_init (&cert) < 0)
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
Daniel P. Berrange 42af21
-	    gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (gnutls_x509_crt_get_expiration_time (cert) < now) {
Daniel P. Berrange 42af21
-	    VNC_DEBUG("The certificate has expired\n");
Daniel P. Berrange 42af21
-	    gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (gnutls_x509_crt_get_activation_time (cert) > now) {
Daniel P. Berrange 42af21
-	    VNC_DEBUG("The certificate is not yet activated\n");
Daniel P. Berrange 42af21
-	    gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (gnutls_x509_crt_get_activation_time (cert) > now) {
Daniel P. Berrange 42af21
-	    VNC_DEBUG("The certificate is not yet activated\n");
Daniel P. Berrange 42af21
-	    gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	gnutls_x509_crt_deinit (cert);
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    return 0;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static int start_auth_vencrypt_subauth(VncState *vs)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    switch (vs->vd->subauth) {
Daniel P. Berrange 42af21
-    case VNC_AUTH_VENCRYPT_TLSNONE:
Daniel P. Berrange 42af21
-    case VNC_AUTH_VENCRYPT_X509NONE:
Daniel P. Berrange 42af21
-       VNC_DEBUG("Accept TLS auth none\n");
Daniel P. Berrange 42af21
-       vnc_write_u32(vs, 0); /* Accept auth completion */
Daniel P. Berrange 42af21
-       vnc_read_when(vs, protocol_client_init, 1);
Daniel P. Berrange 42af21
-       break;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    case VNC_AUTH_VENCRYPT_TLSVNC:
Daniel P. Berrange 42af21
-    case VNC_AUTH_VENCRYPT_X509VNC:
Daniel P. Berrange 42af21
-       VNC_DEBUG("Start TLS auth VNC\n");
Daniel P. Berrange 42af21
-       return start_auth_vnc(vs);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    default: /* Should not be possible, but just in case */
Daniel P. Berrange 42af21
-       VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
Daniel P. Berrange 42af21
-       vnc_write_u8(vs, 1);
Daniel P. Berrange 42af21
-       if (vs->minor >= 8) {
Daniel P. Berrange 42af21
-           static const char err[] = "Unsupported authentication type";
Daniel P. Berrange 42af21
-           vnc_write_u32(vs, sizeof(err));
Daniel P. Berrange 42af21
-           vnc_write(vs, err, sizeof(err));
Daniel P. Berrange 42af21
-       }
Daniel P. Berrange 42af21
-       vnc_client_error(vs);
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    return 0;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static void vnc_handshake_io(void *opaque);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static int vnc_continue_handshake(struct VncState *vs) {
Daniel P. Berrange 42af21
-    int ret;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if ((ret = gnutls_handshake(vs->tls_session)) < 0) {
Daniel P. Berrange 42af21
-       if (!gnutls_error_is_fatal(ret)) {
Daniel P. Berrange 42af21
-           VNC_DEBUG("Handshake interrupted (blocking)\n");
Daniel P. Berrange 42af21
-           if (!gnutls_record_get_direction(vs->tls_session))
Daniel P. Berrange 42af21
-               qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs);
Daniel P. Berrange 42af21
-           else
Daniel P. Berrange 42af21
-               qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs);
Daniel P. Berrange 42af21
-           return 0;
Daniel P. Berrange 42af21
-       }
Daniel P. Berrange 42af21
-       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
Daniel P. Berrange 42af21
-       vnc_client_error(vs);
Daniel P. Berrange 42af21
-       return -1;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if (vs->vd->x509verify) {
Daniel P. Berrange 42af21
-	if (vnc_validate_certificate(vs) < 0) {
Daniel P. Berrange 42af21
-	    VNC_DEBUG("Client verification failed\n");
Daniel P. Berrange 42af21
-	    vnc_client_error(vs);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	} else {
Daniel P. Berrange 42af21
-	    VNC_DEBUG("Client verification passed\n");
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
Daniel P. Berrange 42af21
-    vs->wiremode = VNC_WIREMODE_TLS;
Daniel P. Berrange 42af21
-    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    return start_auth_vencrypt_subauth(vs);
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static void vnc_handshake_io(void *opaque) {
Daniel P. Berrange 42af21
-    struct VncState *vs = (struct VncState *)opaque;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    VNC_DEBUG("Handshake IO continue\n");
Daniel P. Berrange 42af21
-    vnc_continue_handshake(vs);
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-#define NEED_X509_AUTH(vs)			      \
Daniel P. Berrange 42af21
-    ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
Daniel P. Berrange 42af21
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
Daniel P. Berrange 42af21
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static int vnc_start_tls(struct VncState *vs) {
Daniel P. Berrange 42af21
-    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
Daniel P. Berrange 42af21
-    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
Daniel P. Berrange 42af21
-    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
Daniel P. Berrange 42af21
-    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    VNC_DEBUG("Do TLS setup\n");
Daniel P. Berrange 42af21
-    if (vnc_tls_initialize() < 0) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Failed to init TLS\n");
Daniel P. Berrange 42af21
-	vnc_client_error(vs);
Daniel P. Berrange 42af21
-	return -1;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-    if (vs->tls_session == NULL) {
Daniel P. Berrange 42af21
-	if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) {
Daniel P. Berrange 42af21
-	    vnc_client_error(vs);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (gnutls_set_default_priority(vs->tls_session) < 0) {
Daniel P. Berrange 42af21
-	    gnutls_deinit(vs->tls_session);
Daniel P. Berrange 42af21
-	    vs->tls_session = NULL;
Daniel P. Berrange 42af21
-	    vnc_client_error(vs);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) {
Daniel P. Berrange 42af21
-	    gnutls_deinit(vs->tls_session);
Daniel P. Berrange 42af21
-	    vs->tls_session = NULL;
Daniel P. Berrange 42af21
-	    vnc_client_error(vs);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) {
Daniel P. Berrange 42af21
-	    gnutls_deinit(vs->tls_session);
Daniel P. Berrange 42af21
-	    vs->tls_session = NULL;
Daniel P. Berrange 42af21
-	    vnc_client_error(vs);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) {
Daniel P. Berrange 42af21
-	    gnutls_deinit(vs->tls_session);
Daniel P. Berrange 42af21
-	    vs->tls_session = NULL;
Daniel P. Berrange 42af21
-	    vnc_client_error(vs);
Daniel P. Berrange 42af21
-	    return -1;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (NEED_X509_AUTH(vs)) {
Daniel P. Berrange 42af21
-	    gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs);
Daniel P. Berrange 42af21
-	    if (!x509_cred) {
Daniel P. Berrange 42af21
-		gnutls_deinit(vs->tls_session);
Daniel P. Berrange 42af21
-		vs->tls_session = NULL;
Daniel P. Berrange 42af21
-		vnc_client_error(vs);
Daniel P. Berrange 42af21
-		return -1;
Daniel P. Berrange 42af21
-	    }
Daniel P. Berrange 42af21
-	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
Daniel P. Berrange 42af21
-		gnutls_deinit(vs->tls_session);
Daniel P. Berrange 42af21
-		vs->tls_session = NULL;
Daniel P. Berrange 42af21
-		gnutls_certificate_free_credentials(x509_cred);
Daniel P. Berrange 42af21
-		vnc_client_error(vs);
Daniel P. Berrange 42af21
-		return -1;
Daniel P. Berrange 42af21
-	    }
Daniel P. Berrange 42af21
-	    if (vs->vd->x509verify) {
Daniel P. Berrange 42af21
-		VNC_DEBUG("Requesting a client certificate\n");
Daniel P. Berrange 42af21
-		gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
Daniel P. Berrange 42af21
-	    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	} else {
Daniel P. Berrange 42af21
-	    gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
Daniel P. Berrange 42af21
-	    if (!anon_cred) {
Daniel P. Berrange 42af21
-		gnutls_deinit(vs->tls_session);
Daniel P. Berrange 42af21
-		vs->tls_session = NULL;
Daniel P. Berrange 42af21
-		vnc_client_error(vs);
Daniel P. Berrange 42af21
-		return -1;
Daniel P. Berrange 42af21
-	    }
Daniel P. Berrange 42af21
-	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
Daniel P. Berrange 42af21
-		gnutls_deinit(vs->tls_session);
Daniel P. Berrange 42af21
-		vs->tls_session = NULL;
Daniel P. Berrange 42af21
-		gnutls_anon_free_server_credentials(anon_cred);
Daniel P. Berrange 42af21
-		vnc_client_error(vs);
Daniel P. Berrange 42af21
-		return -1;
Daniel P. Berrange 42af21
-	    }
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs);
Daniel P. Berrange 42af21
-	gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push);
Daniel P. Berrange 42af21
-	gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull);
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    VNC_DEBUG("Start TLS handshake process\n");
Daniel P. Berrange 42af21
-    return vnc_continue_handshake(vs);
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    int auth = read_u32(data, 0);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if (auth != vs->vd->subauth) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Rejecting auth %d\n", auth);
Daniel P. Berrange 42af21
-	vnc_write_u8(vs, 0); /* Reject auth */
Daniel P. Berrange 42af21
-	vnc_flush(vs);
Daniel P. Berrange 42af21
-	vnc_client_error(vs);
Daniel P. Berrange 42af21
-    } else {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Accepting auth %d, starting handshake\n", auth);
Daniel P. Berrange 42af21
-	vnc_write_u8(vs, 1); /* Accept auth */
Daniel P. Berrange 42af21
-	vnc_flush(vs);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-	if (vnc_start_tls(vs) < 0) {
Daniel P. Berrange 42af21
-	    VNC_DEBUG("Failed to complete TLS\n");
Daniel P. Berrange 42af21
-	    return 0;
Daniel P. Berrange 42af21
-	}
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-    return 0;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    if (data[0] != 0 ||
Daniel P. Berrange 42af21
-	data[1] != 2) {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
Daniel P. Berrange 42af21
-	vnc_write_u8(vs, 1); /* Reject version */
Daniel P. Berrange 42af21
-	vnc_flush(vs);
Daniel P. Berrange 42af21
-	vnc_client_error(vs);
Daniel P. Berrange 42af21
-    } else {
Daniel P. Berrange 42af21
-	VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
Daniel P. Berrange 42af21
-	vnc_write_u8(vs, 0); /* Accept version */
Daniel P. Berrange 42af21
-	vnc_write_u8(vs, 1); /* Number of sub-auths */
Daniel P. Berrange 42af21
-	vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
Daniel P. Berrange 42af21
-	vnc_flush(vs);
Daniel P. Berrange 42af21
-	vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-    return 0;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static int start_auth_vencrypt(VncState *vs)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    /* Send VeNCrypt version 0.2 */
Daniel P. Berrange 42af21
-    vnc_write_u8(vs, 0);
Daniel P. Berrange 42af21
-    vnc_write_u8(vs, 2);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
Daniel P. Berrange 42af21
-    return 0;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-#endif /* CONFIG_VNC_TLS */
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
 static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     /* We only advertise 1 auth scheme at a time, so client
Daniel P. Berrange 42af21
@@ -2163,17 +1707,19 @@ static int protocol_client_auth(VncState
Daniel P. Berrange 42af21
                vnc_write_u32(vs, 0); /* Accept auth completion */
Daniel P. Berrange 42af21
                vnc_flush(vs);
Daniel P. Berrange 42af21
            }
Daniel P. Berrange 42af21
-           vnc_read_when(vs, protocol_client_init, 1);
Daniel P. Berrange 42af21
+           start_client_init(vs);
Daniel P. Berrange 42af21
            break;
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
        case VNC_AUTH_VNC:
Daniel P. Berrange 42af21
            VNC_DEBUG("Start VNC auth\n");
Daniel P. Berrange 42af21
-           return start_auth_vnc(vs);
Daniel P. Berrange 42af21
+           start_auth_vnc(vs);
Daniel P. Berrange 42af21
+           break;
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 #ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
        case VNC_AUTH_VENCRYPT:
Daniel P. Berrange 42af21
            VNC_DEBUG("Accept VeNCrypt auth\n");;
Daniel P. Berrange 42af21
-           return start_auth_vencrypt(vs);
Daniel P. Berrange 42af21
+           start_auth_vencrypt(vs);
Daniel P. Berrange 42af21
+           break;
Daniel P. Berrange 42af21
 #endif /* CONFIG_VNC_TLS */
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
        default: /* Should not be possible, but just in case */
Daniel P. Berrange 42af21
@@ -2226,7 +1772,7 @@ static int protocol_version(VncState *vs
Daniel P. Berrange 42af21
             VNC_DEBUG("Tell client auth none\n");
Daniel P. Berrange 42af21
             vnc_write_u32(vs, vs->vd->auth);
Daniel P. Berrange 42af21
             vnc_flush(vs);
Daniel P. Berrange 42af21
-            vnc_read_when(vs, protocol_client_init, 1);
Daniel P. Berrange 42af21
+	    start_client_init(vs);
Daniel P. Berrange 42af21
        } else if (vs->vd->auth == VNC_AUTH_VNC) {
Daniel P. Berrange 42af21
             VNC_DEBUG("Tell client VNC auth\n");
Daniel P. Berrange 42af21
             vnc_write_u32(vs, vs->vd->auth);
Daniel P. Berrange 42af21
@@ -2328,61 +1874,6 @@ void vnc_display_init(DisplayState *ds)
Daniel P. Berrange 42af21
     register_displaychangelistener(ds, dcl);
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-#ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-static int vnc_set_x509_credential(VncDisplay *vs,
Daniel P. Berrange 42af21
-				   const char *certdir,
Daniel P. Berrange 42af21
-				   const char *filename,
Daniel P. Berrange 42af21
-				   char **cred,
Daniel P. Berrange 42af21
-				   int ignoreMissing)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    struct stat sb;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    if (*cred) {
Daniel P. Berrange 42af21
-	qemu_free(*cred);
Daniel P. Berrange 42af21
-	*cred = NULL;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    strcpy(*cred, certdir);
Daniel P. Berrange 42af21
-    strcat(*cred, "/");
Daniel P. Berrange 42af21
-    strcat(*cred, filename);
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    VNC_DEBUG("Check %s\n", *cred);
Daniel P. Berrange 42af21
-    if (stat(*cred, &sb) < 0) {
Daniel P. Berrange 42af21
-	qemu_free(*cred);
Daniel P. Berrange 42af21
-	*cred = NULL;
Daniel P. Berrange 42af21
-	if (ignoreMissing && errno == ENOENT)
Daniel P. Berrange 42af21
-	    return 0;
Daniel P. Berrange 42af21
-	return -1;
Daniel P. Berrange 42af21
-    }
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    return 0;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-static int vnc_set_x509_credential_dir(VncDisplay *vs,
Daniel P. Berrange 42af21
-				       const char *certdir)
Daniel P. Berrange 42af21
-{
Daniel P. Berrange 42af21
-    if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
Daniel P. Berrange 42af21
-	goto cleanup;
Daniel P. Berrange 42af21
-    if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0)
Daniel P. Berrange 42af21
-	goto cleanup;
Daniel P. Berrange 42af21
-    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0)
Daniel P. Berrange 42af21
-	goto cleanup;
Daniel P. Berrange 42af21
-    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0)
Daniel P. Berrange 42af21
-	goto cleanup;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    return 0;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
- cleanup:
Daniel P. Berrange 42af21
-    qemu_free(vs->x509cacert);
Daniel P. Berrange 42af21
-    qemu_free(vs->x509cacrl);
Daniel P. Berrange 42af21
-    qemu_free(vs->x509cert);
Daniel P. Berrange 42af21
-    qemu_free(vs->x509key);
Daniel P. Berrange 42af21
-    vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL;
Daniel P. Berrange 42af21
-    return -1;
Daniel P. Berrange 42af21
-}
Daniel P. Berrange 42af21
-#endif /* CONFIG_VNC_TLS */
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 void vnc_display_close(DisplayState *ds)
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
@@ -2402,7 +1893,7 @@ void vnc_display_close(DisplayState *ds)
Daniel P. Berrange 42af21
     vs->auth = VNC_AUTH_INVALID;
Daniel P. Berrange 42af21
 #ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
     vs->subauth = VNC_AUTH_INVALID;
Daniel P. Berrange 42af21
-    vs->x509verify = 0;
Daniel P. Berrange 42af21
+    vs->tls.x509verify = 0;
Daniel P. Berrange 42af21
 #endif
Daniel P. Berrange 42af21
 }
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
@@ -2458,7 +1949,7 @@ int vnc_display_open(DisplayState *ds, c
Daniel P. Berrange 42af21
 	    char *start, *end;
Daniel P. Berrange 42af21
 	    x509 = 1; /* Require x509 certificates */
Daniel P. Berrange 42af21
 	    if (strncmp(options, "x509verify", 10) == 0)
Daniel P. Berrange 42af21
-	        vs->x509verify = 1; /* ...and verify client certs */
Daniel P. Berrange 42af21
+	        vs->tls.x509verify = 1; /* ...and verify client certs */
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 	    /* Now check for 'x509=/some/path' postfix
Daniel P. Berrange 42af21
 	     * and use that to setup x509 certificate/key paths */
Daniel P. Berrange 42af21
@@ -2469,7 +1960,7 @@ int vnc_display_open(DisplayState *ds, c
Daniel P. Berrange 42af21
 		char *path = qemu_strndup(start + 1, len);
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 		VNC_DEBUG("Trying certificate path '%s'\n", path);
Daniel P. Berrange 42af21
-		if (vnc_set_x509_credential_dir(vs, path) < 0) {
Daniel P. Berrange 42af21
+		if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
Daniel P. Berrange 42af21
 		    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
Daniel P. Berrange 42af21
 		    qemu_free(path);
Daniel P. Berrange 42af21
 		    qemu_free(vs->display);
Glauber Costa 8571d0
Index: kvm-84.git-snapshot-20090303/qemu/vnc.h
Glauber Costa 8571d0
===================================================================
Glauber Costa 8571d0
--- kvm-84.git-snapshot-20090303.orig/qemu/vnc.h
Glauber Costa 8571d0
+++ kvm-84.git-snapshot-20090303/qemu/vnc.h
Glauber Costa 8571d0
@@ -32,13 +32,16 @@
Daniel P. Berrange 42af21
 #include "audio/audio.h"
Daniel P. Berrange 42af21
 #include <zlib.h>
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-#ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-#include <gnutls/gnutls.h>
Daniel P. Berrange 42af21
-#include <gnutls/x509.h>
Daniel P. Berrange 42af21
-#endif /* CONFIG_VNC_TLS */
Glauber Costa 8571d0
-
Glauber Costa 8571d0
 #include "keymaps.h"
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
+// #define _VNC_DEBUG 1
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+#ifdef _VNC_DEBUG
Daniel P. Berrange 42af21
+#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
Daniel P. Berrange 42af21
+#else
Daniel P. Berrange 42af21
+#define VNC_DEBUG(fmt, ...) do { } while (0)
Daniel P. Berrange 42af21
+#endif
Glauber Costa 8571d0
+
Daniel P. Berrange 42af21
 /*****************************************************************************
Daniel P. Berrange 42af21
  *
Glauber Costa 8571d0
  * Core data structures
Daniel P. Berrange 42af21
@@ -72,6 +75,11 @@ typedef void VncSendHextileTile(VncState
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 typedef struct VncDisplay VncDisplay;
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
+#ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
+#include "vnc-tls.h"
Daniel P. Berrange 42af21
+#include "vnc-auth-vencrypt.h"
Daniel P. Berrange 42af21
+#endif
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
 struct VncDisplay
Daniel P. Berrange 42af21
 {
Daniel P. Berrange 42af21
     int lsock;
Daniel P. Berrange 42af21
@@ -83,13 +91,8 @@ struct VncDisplay
Daniel P. Berrange 42af21
     char *password;
Daniel P. Berrange 42af21
     int auth;
Daniel P. Berrange 42af21
 #ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-    int subauth;
Daniel P. Berrange 42af21
-    int x509verify;
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-    char *x509cacert;
Daniel P. Berrange 42af21
-    char *x509cacrl;
Daniel P. Berrange 42af21
-    char *x509cert;
Daniel P. Berrange 42af21
-    char *x509key;
Daniel P. Berrange 42af21
+    int subauth; /* Used by VeNCrypt */
Daniel P. Berrange 42af21
+    VncDisplayTLS tls;
Daniel P. Berrange 42af21
 #endif
Daniel P. Berrange 42af21
 };
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
@@ -117,8 +120,7 @@ struct VncState
Daniel P. Berrange 42af21
     char challenge[VNC_AUTH_CHALLENGE_SIZE];
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 #ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-    int wiremode;
Daniel P. Berrange 42af21
-    gnutls_session_t tls_session;
Daniel P. Berrange 42af21
+    VncStateTLS tls;
Daniel P. Berrange 42af21
 #endif
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
     Buffer output;
Daniel P. Berrange 42af21
@@ -162,12 +164,6 @@ enum {
Daniel P. Berrange 42af21
     VNC_AUTH_VENCRYPT = 19
Daniel P. Berrange 42af21
 };
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-#ifdef CONFIG_VNC_TLS
Daniel P. Berrange 42af21
-enum {
Daniel P. Berrange 42af21
-    VNC_WIREMODE_CLEAR,
Daniel P. Berrange 42af21
-    VNC_WIREMODE_TLS,
Daniel P. Berrange 42af21
-};
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
 enum {
Daniel P. Berrange 42af21
     VNC_AUTH_VENCRYPT_PLAIN = 256,
Daniel P. Berrange 42af21
     VNC_AUTH_VENCRYPT_TLSNONE = 257,
Daniel P. Berrange 42af21
@@ -178,12 +174,6 @@ enum {
Daniel P. Berrange 42af21
     VNC_AUTH_VENCRYPT_X509PLAIN = 262,
Daniel P. Berrange 42af21
 };
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
-#define X509_CA_CERT_FILE "ca-cert.pem"
Daniel P. Berrange 42af21
-#define X509_CA_CRL_FILE "ca-crl.pem"
Daniel P. Berrange 42af21
-#define X509_SERVER_KEY_FILE "server-key.pem"
Daniel P. Berrange 42af21
-#define X509_SERVER_CERT_FILE "server-cert.pem"
Daniel P. Berrange 42af21
-
Daniel P. Berrange 42af21
-#endif /* CONFIG_VNC_TLS */
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
 /*****************************************************************************
Daniel P. Berrange 42af21
  *
Daniel P. Berrange 42af21
@@ -254,4 +244,38 @@ enum {
Daniel P. Berrange 42af21
 #define VNC_FEATURE_ZLIB_MASK                (1 << VNC_FEATURE_ZLIB)
Daniel P. Berrange 42af21
 #define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
Daniel P. Berrange 42af21
 
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+/*****************************************************************************
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ * Internal APIs
Daniel P. Berrange 42af21
+ *
Daniel P. Berrange 42af21
+ *****************************************************************************/
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+/* Event loop functions */
Daniel P. Berrange 42af21
+void vnc_client_read(void *opaque);
Daniel P. Berrange 42af21
+void vnc_client_write(void *opaque);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+/* Protocol I/O functions */
Daniel P. Berrange 42af21
+void vnc_write(VncState *vs, const void *data, size_t len);
Daniel P. Berrange 42af21
+void vnc_write_u32(VncState *vs, uint32_t value);
Daniel P. Berrange 42af21
+void vnc_write_s32(VncState *vs, int32_t value);
Daniel P. Berrange 42af21
+void vnc_write_u16(VncState *vs, uint16_t value);
Daniel P. Berrange 42af21
+void vnc_write_u8(VncState *vs, uint8_t value);
Daniel P. Berrange 42af21
+void vnc_flush(VncState *vs);
Daniel P. Berrange 42af21
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+/* Buffer I/O functions */
Daniel P. Berrange 42af21
+uint8_t read_u8(uint8_t *data, size_t offset);
Daniel P. Berrange 42af21
+uint16_t read_u16(uint8_t *data, size_t offset);
Daniel P. Berrange 42af21
+int32_t read_s32(uint8_t *data, size_t offset);
Daniel P. Berrange 42af21
+uint32_t read_u32(uint8_t *data, size_t offset);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+/* Protocol stage functions */
Daniel P. Berrange 42af21
+void vnc_client_error(VncState *vs);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
+void start_client_init(VncState *vs);
Daniel P. Berrange 42af21
+void start_auth_vnc(VncState *vs);
Daniel P. Berrange 42af21
+
Daniel P. Berrange 42af21
 #endif /* __QEMU_VNC_H */