Commit 1cfa7e0a authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/kraxel/tags/pull-vnc-20150318-1' into staging



vnc: fix websockets & QMP.

# gpg: Signature made Wed Mar 18 13:12:35 2015 GMT using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-vnc-20150318-1:
  ui: ensure VNC websockets server checks the ACL if requested
  ui: remove separate gnutls_session for websockets server
  ui: enforce TLS when using websockets server
  ui: fix setup of VNC websockets auth scheme with TLS
  ui: split setup of VNC auth scheme into separate method
  ui: report error if user requests VNC option that is unsupported
  ui: replace printf() calls with VNC_DEBUG
  ui: remove unused 'wiremode' variable in VncState struct
  vnc: Fix QMP change not to use funky error class

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 2259c16d 4a48aaa9
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -93,7 +93,6 @@ static int vnc_start_vencrypt_handshake(struct VncState *vs) {
    }

    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
    vs->tls.wiremode = VNC_WIREMODE_TLS;
    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);

    start_auth_vencrypt_subauth(vs);
+29 −43
Original line number Diff line number Diff line
@@ -334,82 +334,77 @@ static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)

int vnc_tls_client_setup(struct VncState *vs,
                         int needX509Creds) {
    VncStateTLS *tls;

    VNC_DEBUG("Do TLS setup\n");
#ifdef CONFIG_VNC_WS
    if (vs->websocket) {
        tls = &vs->ws_tls;
    } else
#endif /* CONFIG_VNC_WS */
    {
        tls = &vs->tls;
    }
    if (vnc_tls_initialize() < 0) {
        VNC_DEBUG("Failed to init TLS\n");
        vnc_client_error(vs);
        return -1;
    }
    if (tls->session == NULL) {
        if (gnutls_init(&tls->session, GNUTLS_SERVER) < 0) {
    if (vs->tls.session == NULL) {
        if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
            vnc_client_error(vs);
            return -1;
        }

        if (gnutls_set_default_priority(tls->session) < 0) {
            gnutls_deinit(tls->session);
            tls->session = NULL;
        if (gnutls_set_default_priority(vs->tls.session) < 0) {
            gnutls_deinit(vs->tls.session);
            vs->tls.session = NULL;
            vnc_client_error(vs);
            return -1;
        }

        if (vnc_set_gnutls_priority(tls->session, needX509Creds) < 0) {
            gnutls_deinit(tls->session);
            tls->session = NULL;
        if (vnc_set_gnutls_priority(vs->tls.session, needX509Creds) < 0) {
            gnutls_deinit(vs->tls.session);
            vs->tls.session = NULL;
            vnc_client_error(vs);
            return -1;
        }

        if (needX509Creds) {
            gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
            gnutls_certificate_server_credentials x509_cred =
                vnc_tls_initialize_x509_cred(vs->vd);
            if (!x509_cred) {
                gnutls_deinit(tls->session);
                tls->session = NULL;
                gnutls_deinit(vs->tls.session);
                vs->tls.session = NULL;
                vnc_client_error(vs);
                return -1;
            }
            if (gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
                gnutls_deinit(tls->session);
                tls->session = NULL;
            if (gnutls_credentials_set(vs->tls.session,
                                       GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
                gnutls_deinit(vs->tls.session);
                vs->tls.session = NULL;
                gnutls_certificate_free_credentials(x509_cred);
                vnc_client_error(vs);
                return -1;
            }
            if (vs->vd->tls.x509verify) {
                VNC_DEBUG("Requesting a client certificate\n");
                gnutls_certificate_server_set_request (tls->session, GNUTLS_CERT_REQUEST);
                gnutls_certificate_server_set_request(vs->tls.session,
                                                      GNUTLS_CERT_REQUEST);
            }

        } else {
            gnutls_anon_server_credentials_t anon_cred = vnc_tls_initialize_anon_cred();
            gnutls_anon_server_credentials_t anon_cred =
                vnc_tls_initialize_anon_cred();
            if (!anon_cred) {
                gnutls_deinit(tls->session);
                tls->session = NULL;
                gnutls_deinit(vs->tls.session);
                vs->tls.session = NULL;
                vnc_client_error(vs);
                return -1;
            }
            if (gnutls_credentials_set(tls->session, GNUTLS_CRD_ANON, anon_cred) < 0) {
                gnutls_deinit(tls->session);
                tls->session = NULL;
            if (gnutls_credentials_set(vs->tls.session,
                                       GNUTLS_CRD_ANON, anon_cred) < 0) {
                gnutls_deinit(vs->tls.session);
                vs->tls.session = NULL;
                gnutls_anon_free_server_credentials(anon_cred);
                vnc_client_error(vs);
                return -1;
            }
        }

        gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr_t)vs);
        gnutls_transport_set_push_function(tls->session, vnc_tls_push);
        gnutls_transport_set_pull_function(tls->session, vnc_tls_pull);
        gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs);
        gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
        gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
    }
    return 0;
}
@@ -421,16 +416,7 @@ void vnc_tls_client_cleanup(struct VncState *vs)
        gnutls_deinit(vs->tls.session);
        vs->tls.session = NULL;
    }
    vs->tls.wiremode = VNC_WIREMODE_CLEAR;
    g_free(vs->tls.dname);
#ifdef CONFIG_VNC_WS
    if (vs->ws_tls.session) {
        gnutls_deinit(vs->ws_tls.session);
        vs->ws_tls.session = NULL;
    }
    vs->ws_tls.wiremode = VNC_WIREMODE_CLEAR;
    g_free(vs->ws_tls.dname);
#endif /* CONFIG_VNC_WS */
}


+0 −7
Original line number Diff line number Diff line
@@ -33,11 +33,6 @@

#include "qemu/acl.h"

enum {
    VNC_WIREMODE_CLEAR,
    VNC_WIREMODE_TLS,
};

typedef struct VncDisplayTLS VncDisplayTLS;
typedef struct VncStateTLS VncStateTLS;

@@ -55,8 +50,6 @@ struct VncDisplayTLS {

/* Per client state */
struct VncStateTLS {
    /* Whether data is being TLS encrypted yet */
    int wiremode;
    gnutls_session_t session;

    /* Client's Distinguished Name from the x509 cert */
+19 −27
Original line number Diff line number Diff line
@@ -24,16 +24,14 @@
#ifdef CONFIG_VNC_TLS
#include "qemu/sockets.h"

static void vncws_tls_handshake_io(void *opaque);

static int vncws_start_tls_handshake(struct VncState *vs)
{
    int ret = gnutls_handshake(vs->ws_tls.session);
    int ret = gnutls_handshake(vs->tls.session);

    if (ret < 0) {
        if (!gnutls_error_is_fatal(ret)) {
            VNC_DEBUG("Handshake interrupted (blocking)\n");
            if (!gnutls_record_get_direction(vs->ws_tls.session)) {
            if (!gnutls_record_get_direction(vs->tls.session)) {
                qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io,
                                    NULL, vs);
            } else {
@@ -47,40 +45,34 @@ static int vncws_start_tls_handshake(struct VncState *vs)
        return -1;
    }

    if (vs->vd->tls.x509verify) {
        if (vnc_tls_validate_certificate(vs) < 0) {
            VNC_DEBUG("Client verification failed\n");
            vnc_client_error(vs);
            return -1;
        } else {
            VNC_DEBUG("Client verification passed\n");
        }
    }

    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
    vs->ws_tls.wiremode = VNC_WIREMODE_TLS;
    qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs);

    return 0;
}

static void vncws_tls_handshake_io(void *opaque)
void vncws_tls_handshake_io(void *opaque)
{
    struct VncState *vs = (struct VncState *)opaque;

    VNC_DEBUG("Handshake IO continue\n");
    vncws_start_tls_handshake(vs);
}

void vncws_tls_handshake_peek(void *opaque)
{
    VncState *vs = opaque;
    long ret;

    if (!vs->ws_tls.session) {
        char peek[4];
        ret = qemu_recv(vs->csock, peek, sizeof(peek), MSG_PEEK);
        if (ret && (strncmp(peek, "\x16", 1) == 0
                    || strncmp(peek, "\x80", 1) == 0)) {
            VNC_DEBUG("TLS Websocket connection recognized");
            vnc_tls_client_setup(vs, 1);
            vncws_start_tls_handshake(vs);
        } else {
            vncws_handshake_read(vs);
    if (!vs->tls.session) {
        VNC_DEBUG("TLS Websocket setup\n");
        if (vnc_tls_client_setup(vs, vs->vd->tls.x509cert != NULL) < 0) {
            return;
        }
    } else {
        qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs);
    }
    VNC_DEBUG("Handshake IO continue\n");
    vncws_start_tls_handshake(vs);
}
#endif /* CONFIG_VNC_TLS */

+1 −1
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ enum {
};

#ifdef CONFIG_VNC_TLS
void vncws_tls_handshake_peek(void *opaque);
void vncws_tls_handshake_io(void *opaque);
#endif /* CONFIG_VNC_TLS */
void vncws_handshake_read(void *opaque);
long vnc_client_write_ws(VncState *vs);
Loading