All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC
@ 2017-05-15 23:03 Simon Waterman
  2017-05-15 23:03 ` [PATCH RFC 1/6] qemu-xen-trad: sasl: expose vnc API to SASL auth Simon Waterman
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Simon Waterman @ 2017-05-15 23:03 UTC (permalink / raw)
  To: xen-devel; +Cc: dunlapg, ian.jackson

This patch series back-ports SASL authentication from
upstream QEMU to the VNC server in qemu-xen-traditional.
It enables authentication to the VNC console of a domain
to be controlled using any SASL mechanism when using an
IOEMU stubdom.

SASL can be used with or without X509 certificates.

The option is currently enabled during build by adding
--enable-vnc-sasl to the configure line in xen-setup in the
root of the QEMU tree.

SASL auth can be enabled for a domain using the 'vnclisten'
option in the Xen config file:
vnclisten="0.0.0.0:5,tls,x509verify=/etc/ssl,sasl"

Details of how to configure SASL in QEMU can be found here:
https://qemu.weilnetz.de/doc/qemu-doc.html#vnc_005fsec_005fsasl

 Makefile.target |    6
 configure       |   34 +++
 vnc-auth-sasl.c |  613 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 vnc-auth-sasl.h |   67 ++++++
 vnc.c           |  533 ++++++++++++++++++++++++++++--------------------
 vnc.h           |  231 ++++++++++++++++++++-
 6 files changed, 1257 insertions(+), 227 deletions(-)


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH RFC 1/6] qemu-xen-trad: sasl: expose vnc API to SASL auth
  2017-05-15 23:03 [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC Simon Waterman
@ 2017-05-15 23:03 ` Simon Waterman
  2017-05-15 23:03 ` [PATCH RFC 2/6] qemu-xen-trad: sasl: define SASL auth API Simon Waterman
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Simon Waterman @ 2017-05-15 23:03 UTC (permalink / raw)
  To: xen-devel; +Cc: dunlapg, ian.jackson, Simon Waterman

Expose minimum VNC API to support SASL auth.  This is mainly the
VncState structure and a subset of the API funcs.

The layout of the file is modelled on the upstream QEMU vnc.h.

Signed-off-by: Simon Waterman <watermansrdev@gmail.com>
---
 vnc.h | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 222 insertions(+), 9 deletions(-)

diff --git a/vnc.h b/vnc.h
index 6981606..66bed0c 100644
--- a/vnc.h
+++ b/vnc.h
@@ -1,5 +1,183 @@
-#ifndef __VNCTIGHT_H
-#define __VNCTIGHT_H
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef __QEMU_VNC_H
+#define __QEMU_VNC_H
+
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+
+// #define _VNC_DEBUG 1
+
+#ifdef _VNC_DEBUG
+#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+
+#if defined(CONFIG_VNC_TLS) && _VNC_DEBUG >= 2
+/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
+static void vnc_debug_gnutls_log(int level, const char* str) {
+    VNC_DEBUG("%d %s", level, str);
+}
+#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
+#else
+#define VNC_DEBUG(fmt, ...) do { } while (0)
+#endif
+
+/*****************************************************************************
+ *
+ * Core data structures
+ *
+ *****************************************************************************/
+
+typedef struct Buffer
+{
+    size_t capacity;
+    size_t offset;
+    uint8_t *buffer;
+} Buffer;
+
+typedef struct VncState VncState;
+
+typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
+
+typedef void VncWritePixels(VncState *vs, void *data, int size);
+
+typedef void VncSendHextileTile(VncState *vs,
+                                int x, int y, int w, int h,
+                                void *last_bg,
+                                void *last_fg,
+                                int *has_bg, int *has_fg);
+
+#include "vnc_keysym.h"
+#include "keymaps.c"
+
+#ifdef CONFIG_VNC_TLS
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#endif /* CONFIG_VNC_TLS */
+
+#ifdef CONFIG_VNC_SASL
+#include "vnc-auth-sasl.h"
+#endif
+
+#define VNC_AUTH_CHALLENGE_SIZE 16
+
+#define QUEUE_ALLOC_UNIT 10
+
+typedef struct _QueueItem
+{
+    int x, y, w, h;
+    int32_t enc;
+    struct _QueueItem *next;
+} QueueItem;
+
+typedef struct _Queue
+{
+    QueueItem *queue_start;
+    int start_count;
+    QueueItem *queue_end;
+    int end_count;
+} Queue;
+
+struct VncState
+{
+    QEMUTimer *timer;
+    int timer_interval;
+    int64_t last_update_time;
+    int lsock;
+    int csock;
+    DisplayState *ds;
+    uint64_t *dirty_row;        /* screen regions which are possibly dirty */
+    int dirty_pixel_shift;
+    uint64_t *update_row;       /* outstanding updates */
+    int has_update;             /* there's outstanding updates in the
+                                 * visible area */
+
+    int update_requested;       /* the client requested an update */
+
+    uint8_t *old_data;
+    int has_resize;
+    int has_hextile;
+    int has_pointer_type_change;
+    int has_WMVi;
+    int absolute;
+    int last_x;
+    int last_y;
+
+    int major;
+    int minor;
+
+    char *display;
+    char *password;
+    int auth;
+#ifdef CONFIG_VNC_TLS
+    int subauth;
+    int x509verify;
+
+    char *x509cacert;
+    char *x509cacrl;
+    char *x509cert;
+    char *x509key;
+#endif
+    char challenge[VNC_AUTH_CHALLENGE_SIZE];
+    int switchbpp;
+
+#ifdef CONFIG_VNC_TLS
+    int wiremode;
+    gnutls_session_t tls_session;
+#endif
+
+#ifdef CONFIG_VNC_SASL
+    VncStateSASL sasl;
+#endif
+
+    Buffer output;
+    Buffer input;
+
+    Queue upqueue;
+
+    kbd_layout_t *kbd_layout;
+    /* current output mode information */
+    VncWritePixels *write_pixels;
+    VncSendHextileTile *send_hextile_tile;
+    DisplaySurface clientds, serverds;
+
+    VncReadEvent *read_handler;
+    size_t read_handler_expect;
+
+    int visible_x;
+    int visible_y;
+    int visible_w;
+    int visible_h;
+
+    /* input */
+    uint8_t modifiers_state[256];
+};
+
+static VncState *vnc_state; /* needed for info vnc */
 
 /*****************************************************************************
  *
@@ -16,16 +194,12 @@ enum {
     VNC_AUTH_TIGHT = 16,
     VNC_AUTH_ULTRA = 17,
     VNC_AUTH_TLS = 18,
-    VNC_AUTH_VENCRYPT = 19
+    VNC_AUTH_VENCRYPT = 19,
+    VNC_AUTH_SASL = 20,     /* Supported in GTK-VNC & VINO */
 };
 
 #ifdef CONFIG_VNC_TLS
 enum {
-    VNC_WIREMODE_CLEAR,
-    VNC_WIREMODE_TLS,
-};
-
-enum {
     VNC_AUTH_VENCRYPT_PLAIN = 256,
     VNC_AUTH_VENCRYPT_TLSNONE = 257,
     VNC_AUTH_VENCRYPT_TLSVNC = 258,
@@ -33,6 +207,8 @@ enum {
     VNC_AUTH_VENCRYPT_X509NONE = 260,
     VNC_AUTH_VENCRYPT_X509VNC = 261,
     VNC_AUTH_VENCRYPT_X509PLAIN = 262,
+    VNC_AUTH_VENCRYPT_X509SASL = 263,
+    VNC_AUTH_VENCRYPT_TLSSASL = 264,
 };
 
 #define X509_CA_CERT_FILE "ca-cert.pem"
@@ -111,4 +287,41 @@ enum {
 #define VNC_FEATURE_ZLIB_MASK                (1 << VNC_FEATURE_ZLIB)
 #define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
 
-#endif /* __VNCTIGHT_H */
+/*****************************************************************************
+ *
+ * Internal APIs
+ *
+ *****************************************************************************/
+
+/* Event loop functions */
+void vnc_client_read(void *opaque);
+
+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
+
+/* Protocol I/O functions */
+void vnc_write(VncState *vs, const void *data, size_t len);
+void vnc_write_u32(VncState *vs, uint32_t value);
+void vnc_write_u8(VncState *vs, uint8_t value);
+void vnc_flush(VncState *vs);
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
+
+/* Buffer I/O functions */
+uint32_t read_u32(uint8_t *data, size_t offset);
+
+/* Protocol stage functions */
+void vnc_client_error(VncState *vs);
+int vnc_client_io_error(VncState *vs, int ret, int last_errno);
+
+void start_client_init(VncState *vs);
+
+/* Buffer management */
+void buffer_reserve(Buffer *buffer, size_t len);
+void buffer_append(Buffer *buffer, const void *data, size_t len);
+
+/* Misc helpers */
+
+char *vnc_socket_local_addr(const char *format, int fd);
+char *vnc_socket_remote_addr(const char *format, int fd);
+
+#endif /* __QEMU_VNC_H */
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH RFC 2/6] qemu-xen-trad: sasl: define SASL auth API
  2017-05-15 23:03 [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC Simon Waterman
  2017-05-15 23:03 ` [PATCH RFC 1/6] qemu-xen-trad: sasl: expose vnc API to SASL auth Simon Waterman
@ 2017-05-15 23:03 ` Simon Waterman
  2017-05-15 23:03 ` [PATCH RFC 3/6] qemu-xen-trad: sasl: implement SASL auth Simon Waterman
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Simon Waterman @ 2017-05-15 23:03 UTC (permalink / raw)
  To: xen-devel; +Cc: dunlapg, ian.jackson, Simon Waterman

Add the SASL auth API to hook into vnc.c.  Taken from upstream
with minor changes to remove ACL support, which isn't in
qemu-xen-traditional yet.

Signed-off-by: Simon Waterman <watermansrdev@gmail.com>
---
 vnc-auth-sasl.h | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100644 vnc-auth-sasl.h

diff --git a/vnc-auth-sasl.h b/vnc-auth-sasl.h
new file mode 100644
index 0000000..42a049f
--- /dev/null
+++ b/vnc-auth-sasl.h
@@ -0,0 +1,67 @@
+/*
+ * QEMU VNC display driver: SASL auth protocol
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#ifndef __QEMU_VNC_AUTH_SASL_H__
+#define __QEMU_VNC_AUTH_SASL_H__
+
+
+#include <sasl/sasl.h>
+
+typedef struct VncStateSASL VncStateSASL;
+
+struct VncStateSASL {
+    sasl_conn_t *conn;
+    /* If we want to negotiate an SSF layer with client */
+    bool wantSSF;
+    /* If we are now running the SSF layer */
+    bool runSSF;
+    /*
+     * If this is non-zero, then wait for that many bytes
+     * to be written plain, before switching to SSF encoding
+     * This allows the VNC auth result to finish being
+     * written in plain.
+     */
+    unsigned int waitWriteSSF;
+
+    /*
+     * Buffering encoded data to allow more clear data
+     * to be stuffed onto the output buffer
+     */
+    const uint8_t *encoded;
+    unsigned int encodedLength;
+    unsigned int encodedOffset;
+    char *username;
+    char *mechlist;
+};
+
+void vnc_sasl_client_cleanup(VncState *vs);
+
+long vnc_client_read_sasl(VncState *vs);
+long vnc_client_write_sasl(VncState *vs);
+
+void start_auth_sasl(VncState *vs);
+
+#endif /* __QEMU_VNC_AUTH_SASL_H__ */
+
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH RFC 3/6] qemu-xen-trad: sasl: implement SASL auth
  2017-05-15 23:03 [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC Simon Waterman
  2017-05-15 23:03 ` [PATCH RFC 1/6] qemu-xen-trad: sasl: expose vnc API to SASL auth Simon Waterman
  2017-05-15 23:03 ` [PATCH RFC 2/6] qemu-xen-trad: sasl: define SASL auth API Simon Waterman
@ 2017-05-15 23:03 ` Simon Waterman
  2017-05-15 23:03 ` [PATCH RFC 4/6] qemu-xen-trad: sasl: compatibility with vnc.h Simon Waterman
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Simon Waterman @ 2017-05-15 23:03 UTC (permalink / raw)
  To: xen-devel; +Cc: dunlapg, ian.jackson, Simon Waterman

Taken almost directly from upstream QEMU with minor changes:
1. Replace g_free etc. with standard equivalents
2. Remove ACL support, which is not in qemu-xen-traditional yet.

Signed-off-by: Simon Waterman <watermansrdev@gmail.com>
---
 vnc-auth-sasl.c | 613 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 613 insertions(+)
 create mode 100644 vnc-auth-sasl.c

diff --git a/vnc-auth-sasl.c b/vnc-auth-sasl.c
new file mode 100644
index 0000000..e3d2efb
--- /dev/null
+++ b/vnc-auth-sasl.c
@@ -0,0 +1,613 @@
+/*
+ * QEMU VNC display driver: SASL auth protocol
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vnc.h"
+
+/* Max amount of data we send/recv for SASL steps to prevent DOS */
+#define SASL_DATA_MAX_LEN (1024 * 1024)
+
+
+void vnc_sasl_client_cleanup(VncState *vs)
+{
+    if (vs->sasl.conn) {
+        vs->sasl.runSSF = false;
+        vs->sasl.wantSSF = false;
+        vs->sasl.waitWriteSSF = 0;
+        vs->sasl.encodedLength = vs->sasl.encodedOffset = 0;
+        vs->sasl.encoded = NULL;
+        free(vs->sasl.username);
+        free(vs->sasl.mechlist);
+        vs->sasl.username = vs->sasl.mechlist = NULL;
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+    }
+}
+
+
+long vnc_client_write_sasl(VncState *vs)
+{
+    long ret;
+
+    VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd "
+              "Encoded: %p size %d offset %d\n",
+              vs->output.buffer, vs->output.capacity, vs->output.offset,
+              vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset);
+
+    if (!vs->sasl.encoded) {
+        int err;
+        err = sasl_encode(vs->sasl.conn,
+                          (char *)vs->output.buffer,
+                          vs->output.offset,
+                          (const char **)&vs->sasl.encoded,
+                          &vs->sasl.encodedLength);
+        if (err != SASL_OK)
+            return vnc_client_io_error(vs, -1, EIO);
+
+        vs->sasl.encodedOffset = 0;
+    }
+
+    ret = vnc_client_write_buf(vs,
+                               vs->sasl.encoded + vs->sasl.encodedOffset,
+                               vs->sasl.encodedLength - vs->sasl.encodedOffset);
+    if (!ret)
+        return 0;
+
+    vs->sasl.encodedOffset += ret;
+    if (vs->sasl.encodedOffset == vs->sasl.encodedLength) {
+        vs->output.offset = 0;
+        vs->sasl.encoded = NULL;
+        vs->sasl.encodedOffset = vs->sasl.encodedLength = 0;
+    }
+
+    /* Can't merge this block with one above, because
+     * someone might have written more unencrypted
+     * data in vs->output while we were processing
+     * SASL encoded output
+     */
+    if (vs->output.offset == 0) {
+        qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs);
+    }
+
+    return ret;
+}
+
+
+long vnc_client_read_sasl(VncState *vs)
+{
+    long ret;
+    uint8_t encoded[4096];
+    const char *decoded;
+    unsigned int decodedLen;
+    int err;
+
+    ret = vnc_client_read_buf(vs, encoded, sizeof(encoded));
+    if (!ret)
+        return 0;
+
+    err = sasl_decode(vs->sasl.conn,
+                      (char *)encoded, ret,
+                      &decoded, &decodedLen);
+
+    if (err != SASL_OK)
+        return vnc_client_io_error(vs, -1, -EIO);
+    VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n",
+              encoded, ret, decoded, decodedLen);
+    buffer_reserve(&vs->input, decodedLen);
+    buffer_append(&vs->input, decoded, decodedLen);
+    return decodedLen;
+}
+
+
+static int vnc_auth_sasl_check_access(VncState *vs)
+{
+    const void *val;
+    int err;
+    int allow;
+
+    err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
+    if (err != SASL_OK) {
+        VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n",
+                  err, sasl_errstring(err, NULL, NULL));
+        return -1;
+    }
+    if (val == NULL) {
+        VNC_DEBUG("no client username was found, denying access\n");
+        return -1;
+    }
+    VNC_DEBUG("SASL client username %s\n", (const char *)val);
+
+    vs->sasl.username = strdup((const char*)val);
+
+    return 0;
+}
+
+static int vnc_auth_sasl_check_ssf(VncState *vs)
+{
+    const void *val;
+    int err, ssf;
+
+    if (!vs->sasl.wantSSF)
+        return 1;
+
+    err = sasl_getprop(vs->sasl.conn, SASL_SSF, &val);
+    if (err != SASL_OK)
+        return 0;
+
+    ssf = *(const int *)val;
+    VNC_DEBUG("negotiated an SSF of %d\n", ssf);
+    if (ssf < 56)
+        return 0; /* 56 is good for Kerberos */
+
+    /* Only setup for read initially, because we're about to send an RPC
+     * reply which must be in plain text. When the next incoming RPC
+     * arrives, we'll switch on writes too
+     *
+     * cf qemudClientReadSASL  in qemud.c
+     */
+    vs->sasl.runSSF = 1;
+
+    /* We have a SSF that's good enough */
+    return 1;
+}
+
+/*
+ * Step Msg
+ *
+ * Input from client:
+ *
+ * u32 clientin-length
+ * u8-array clientin-string
+ *
+ * Output to client:
+ *
+ * u32 serverout-length
+ * u8-array serverout-strin
+ * u8 continue
+ */
+
+static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len);
+
+static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t datalen = len;
+    const char *serverout;
+    unsigned int serveroutlen;
+    int err;
+    char *clientdata = NULL;
+
+    /* NB, distinction of NULL vs "" is *critical* in SASL */
+    if (datalen) {
+        clientdata = (char*)data;
+        clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */
+        datalen--; /* Don't count NULL byte when passing to _start() */
+    }
+
+    VNC_DEBUG("Step using SASL Data %p (%d bytes)\n",
+              clientdata, datalen);
+    err = sasl_server_step(vs->sasl.conn,
+                           clientdata,
+                           datalen,
+                           &serverout,
+                           &serveroutlen);
+    if (err != SASL_OK &&
+        err != SASL_CONTINUE) {
+        VNC_DEBUG("sasl step failed %d (%s)\n",
+                  err, sasl_errdetail(vs->sasl.conn));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    if (serveroutlen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("sasl step reply data too long %d\n",
+                  serveroutlen);
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
+              serveroutlen, serverout ? 0 : 1);
+
+    if (serveroutlen) {
+        vnc_write_u32(vs, serveroutlen + 1);
+        vnc_write(vs, serverout, serveroutlen + 1);
+    } else {
+        vnc_write_u32(vs, 0);
+    }
+
+    /* Whether auth is complete */
+    vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
+
+    if (err == SASL_CONTINUE) {
+        VNC_DEBUG("%s", "Authentication must continue\n");
+        /* Wait for step length */
+        vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
+    } else {
+        if (!vnc_auth_sasl_check_ssf(vs)) {
+            VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
+            goto authreject;
+        }
+
+        /* Check username whitelist ACL */
+        if (vnc_auth_sasl_check_access(vs) < 0) {
+            VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
+            goto authreject;
+        }
+
+        VNC_DEBUG("Authentication successful %d\n", vs->csock);
+        vnc_write_u32(vs, 0); /* Accept auth */
+        /*
+         * Delay writing in SSF encoded mode until pending output
+         * buffer is written
+         */
+        if (vs->sasl.runSSF)
+            vs->sasl.waitWriteSSF = vs->output.offset;
+        start_client_init(vs);
+    }
+
+    return 0;
+
+ authreject:
+    vnc_write_u32(vs, 1); /* Reject auth */
+    vnc_write_u32(vs, sizeof("Authentication failed"));
+    vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
+    vnc_flush(vs);
+    vnc_client_error(vs);
+    return -1;
+
+ authabort:
+    vnc_client_error(vs);
+    return -1;
+}
+
+static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t steplen = read_u32(data, 0);
+    VNC_DEBUG("Got client step len %d\n", steplen);
+    if (steplen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("Too much SASL data %d\n", steplen);
+        vnc_client_error(vs);
+        return -1;
+    }
+
+    if (steplen == 0)
+        return protocol_client_auth_sasl_step(vs, NULL, 0);
+    else
+        vnc_read_when(vs, protocol_client_auth_sasl_step, steplen);
+    return 0;
+}
+
+/*
+ * Start Msg
+ *
+ * Input from client:
+ *
+ * u32 clientin-length
+ * u8-array clientin-string
+ *
+ * Output to client:
+ *
+ * u32 serverout-length
+ * u8-array serverout-strin
+ * u8 continue
+ */
+
+#define SASL_DATA_MAX_LEN (1024 * 1024)
+
+static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t datalen = len;
+    const char *serverout;
+    unsigned int serveroutlen;
+    int err;
+    char *clientdata = NULL;
+
+    /* NB, distinction of NULL vs "" is *critical* in SASL */
+    if (datalen) {
+        clientdata = (char*)data;
+        clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */
+        datalen--; /* Don't count NULL byte when passing to _start() */
+    }
+
+    VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n",
+              vs->sasl.mechlist, clientdata, datalen);
+    err = sasl_server_start(vs->sasl.conn,
+                            vs->sasl.mechlist,
+                            clientdata,
+                            datalen,
+                            &serverout,
+                            &serveroutlen);
+    if (err != SASL_OK &&
+        err != SASL_CONTINUE) {
+        VNC_DEBUG("sasl start failed %d (%s)\n",
+                  err, sasl_errdetail(vs->sasl.conn));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+    if (serveroutlen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("sasl start reply data too long %d\n",
+                  serveroutlen);
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
+              serveroutlen, serverout ? 0 : 1);
+
+    if (serveroutlen) {
+        vnc_write_u32(vs, serveroutlen + 1);
+        vnc_write(vs, serverout, serveroutlen + 1);
+    } else {
+        vnc_write_u32(vs, 0);
+    }
+
+    /* Whether auth is complete */
+    vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
+
+    if (err == SASL_CONTINUE) {
+        VNC_DEBUG("%s", "Authentication must continue\n");
+        /* Wait for step length */
+        vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
+    } else {
+        if (!vnc_auth_sasl_check_ssf(vs)) {
+            VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
+            goto authreject;
+        }
+
+        /* Check username whitelist ACL */
+        if (vnc_auth_sasl_check_access(vs) < 0) {
+            VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
+            goto authreject;
+        }
+
+        VNC_DEBUG("Authentication successful %d\n", vs->csock);
+        vnc_write_u32(vs, 0); /* Accept auth */
+        start_client_init(vs);
+    }
+
+    return 0;
+
+ authreject:
+    vnc_write_u32(vs, 1); /* Reject auth */
+    vnc_write_u32(vs, sizeof("Authentication failed"));
+    vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
+    vnc_flush(vs);
+    vnc_client_error(vs);
+    return -1;
+
+ authabort:
+    vnc_client_error(vs);
+    return -1;
+}
+
+static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t startlen = read_u32(data, 0);
+    VNC_DEBUG("Got client start len %d\n", startlen);
+    if (startlen > SASL_DATA_MAX_LEN) {
+        VNC_DEBUG("Too much SASL data %d\n", startlen);
+        vnc_client_error(vs);
+        return -1;
+    }
+
+    if (startlen == 0)
+        return protocol_client_auth_sasl_start(vs, NULL, 0);
+
+    vnc_read_when(vs, protocol_client_auth_sasl_start, startlen);
+    return 0;
+}
+
+static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
+{
+    char *mechname = strndup((const char *) data, len);
+    VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
+              mechname, vs->sasl.mechlist);
+
+    if (strncmp(vs->sasl.mechlist, mechname, len) == 0) {
+        if (vs->sasl.mechlist[len] != '\0' &&
+            vs->sasl.mechlist[len] != ',') {
+            VNC_DEBUG("One %d", vs->sasl.mechlist[len]);
+            goto fail;
+        }
+    } else {
+        char *offset = strstr(vs->sasl.mechlist, mechname);
+        VNC_DEBUG("Two %p\n", offset);
+        if (!offset) {
+            goto fail;
+        }
+        VNC_DEBUG("Two '%s'\n", offset);
+        if (offset[-1] != ',' ||
+            (offset[len] != '\0'&&
+             offset[len] != ',')) {
+            goto fail;
+        }
+    }
+
+    free(vs->sasl.mechlist);
+    vs->sasl.mechlist = mechname;
+
+    VNC_DEBUG("Validated mechname '%s'\n", mechname);
+    vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4);
+    return 0;
+
+ fail:
+    vnc_client_error(vs);
+    free(mechname);
+    return -1;
+}
+
+static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len)
+{
+    uint32_t mechlen = read_u32(data, 0);
+    VNC_DEBUG("Got client mechname len %d\n", mechlen);
+    if (mechlen > 100) {
+        VNC_DEBUG("Too long SASL mechname data %d\n", mechlen);
+        vnc_client_error(vs);
+        return -1;
+    }
+    if (mechlen < 1) {
+        VNC_DEBUG("Too short SASL mechname %d\n", mechlen);
+        vnc_client_error(vs);
+        return -1;
+    }
+    vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen);
+    return 0;
+}
+
+void start_auth_sasl(VncState *vs)
+{
+    const char *mechlist = NULL;
+    sasl_security_properties_t secprops;
+    int err;
+    char *localAddr, *remoteAddr;
+    int mechlistlen;
+
+    VNC_DEBUG("Initialize SASL auth %d\n", vs->csock);
+
+    /* Get local & remote client addresses in form  IPADDR;PORT */
+    if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock)))
+        goto authabort;
+
+    if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) {
+        free(localAddr);
+        goto authabort;
+    }
+
+    err = sasl_server_new("vnc",
+                          NULL, /* FQDN - just delegates to gethostname */
+                          NULL, /* User realm */
+                          localAddr,
+                          remoteAddr,
+                          NULL, /* Callbacks, not needed */
+                          SASL_SUCCESS_DATA,
+                          &vs->sasl.conn);
+    free(localAddr);
+    free(remoteAddr);
+    localAddr = remoteAddr = NULL;
+
+    if (err != SASL_OK) {
+        VNC_DEBUG("sasl context setup failed %d (%s)",
+                  err, sasl_errstring(err, NULL, NULL));
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+#ifdef CONFIG_VNC_TLS
+    /* Inform SASL that we've got an external SSF layer from TLS/x509 */
+    if (vs->auth == VNC_AUTH_VENCRYPT &&
+        vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
+        gnutls_cipher_algorithm_t cipher;
+        sasl_ssf_t ssf;
+
+        cipher = gnutls_cipher_get(vs->tls_session);
+        if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
+            VNC_DEBUG("%s", "cannot TLS get cipher size\n");
+            sasl_dispose(&vs->sasl.conn);
+            vs->sasl.conn = NULL;
+            goto authabort;
+        }
+        ssf *= 8; /* tls key size is bytes, sasl wants bits */
+
+        err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
+        if (err != SASL_OK) {
+            VNC_DEBUG("cannot set SASL external SSF %d (%s)\n",
+                      err, sasl_errstring(err, NULL, NULL));
+            sasl_dispose(&vs->sasl.conn);
+            vs->sasl.conn = NULL;
+            goto authabort;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        vs->sasl.wantSSF = 1;
+
+    memset (&secprops, 0, sizeof secprops);
+    /* Inform SASL that we've got an external SSF layer from TLS */
+    if (strncmp(vs->display, "unix:", 5) == 0
+#ifdef CONFIG_VNC_TLS
+        /* Disable SSF, if using TLS+x509+SASL only. TLS without x509
+           is not sufficiently strong */
+        || (vs->auth == VNC_AUTH_VENCRYPT &&
+            vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)
+#endif /* CONFIG_VNC_TLS */
+        ) {
+        /* If we've got TLS or UNIX domain sock, we don't care about SSF */
+        secprops.min_ssf = 0;
+        secprops.max_ssf = 0;
+        secprops.maxbufsize = 8192;
+        secprops.security_flags = 0;
+    } else {
+        /* Plain TCP, better get an SSF layer */
+        secprops.min_ssf = 56; /* Good enough to require kerberos */
+        secprops.max_ssf = 100000; /* Arbitrary big number */
+        secprops.maxbufsize = 8192;
+        /* Forbid any anonymous or trivially crackable auth */
+        secprops.security_flags =
+            SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
+    }
+
+    err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops);
+    if (err != SASL_OK) {
+        VNC_DEBUG("cannot set SASL security props %d (%s)\n",
+                  err, sasl_errstring(err, NULL, NULL));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+
+    err = sasl_listmech(vs->sasl.conn,
+                        NULL, /* Don't need to set user */
+                        "", /* Prefix */
+                        ",", /* Separator */
+                        "", /* Suffix */
+                        &mechlist,
+                        NULL,
+                        NULL);
+    if (err != SASL_OK) {
+        VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n",
+                  err, sasl_errdetail(vs->sasl.conn));
+        sasl_dispose(&vs->sasl.conn);
+        vs->sasl.conn = NULL;
+        goto authabort;
+    }
+    VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);
+
+    vs->sasl.mechlist = strdup(mechlist);
+    mechlistlen = strlen(mechlist);
+    vnc_write_u32(vs, mechlistlen);
+    vnc_write(vs, mechlist, mechlistlen);
+    vnc_flush(vs);
+
+    VNC_DEBUG("Wait for client mechname length\n");
+    vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4);
+
+    return;
+
+ authabort:
+    vnc_client_error(vs);
+}
+
+
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH RFC 4/6] qemu-xen-trad: sasl: compatibility with vnc.h
  2017-05-15 23:03 [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC Simon Waterman
                   ` (2 preceding siblings ...)
  2017-05-15 23:03 ` [PATCH RFC 3/6] qemu-xen-trad: sasl: implement SASL auth Simon Waterman
@ 2017-05-15 23:03 ` Simon Waterman
  2017-05-15 23:03 ` [PATCH RFC 5/6] qemu-xen-trad: sasl: introduce SASL authentication and encryption layer Simon Waterman
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Simon Waterman @ 2017-05-15 23:03 UTC (permalink / raw)
  To: xen-devel; +Cc: dunlapg, ian.jackson, Simon Waterman

This change adjusts vnc.c for compatibility with the API defined
in vnc.h.

Signed-off-by: Simon Waterman <watermansrdev@gmail.com>
---
 vnc.c | 212 +++++++++---------------------------------------------------------
 1 file changed, 27 insertions(+), 185 deletions(-)

diff --git a/vnc.c b/vnc.c
index 0e61197..728efec 100644
--- a/vnc.c
+++ b/vnc.c
@@ -24,6 +24,7 @@
  * THE SOFTWARE.
  */
 
+#include "vnc.h"
 #include "qemu-common.h"
 #include "console.h"
 #include "sysemu.h"
@@ -50,8 +51,6 @@
    minimised vncviewer reasonably quickly. */
 #define VNC_MAX_UPDATE_INTERVAL   5000
 
-#include "vnc_keysym.h"
-#include "keymaps.c"
 #include "d3des.h"
 
 #ifdef CONFIG_VNC_TLS
@@ -59,21 +58,6 @@
 #include <gnutls/x509.h>
 #endif /* CONFIG_VNC_TLS */
 
-// #define _VNC_DEBUG 1
-
-#ifdef _VNC_DEBUG
-#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-
-#if defined(CONFIG_VNC_TLS) && _VNC_DEBUG >= 2
-/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
-static void vnc_debug_gnutls_log(int level, const char* str) {
-    VNC_DEBUG("%d %s", level, str);
-}
-#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
-#else
-#define VNC_DEBUG(fmt, ...) do { } while (0)
-#endif
-
 #define count_bits(c, v) { \
     for (c = 0; v; v >>= 1) \
     { \
@@ -81,157 +65,13 @@ static void vnc_debug_gnutls_log(int level, const char* str) {
     } \
 }
 
-typedef struct Buffer
-{
-    size_t capacity;
-    size_t offset;
-    uint8_t *buffer;
-} Buffer;
-
-typedef struct VncState VncState;
-
-typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
-
-typedef void VncWritePixels(VncState *vs, void *data, int size);
-
-typedef void VncSendHextileTile(VncState *vs,
-                                int x, int y, int w, int h,
-                                void *last_bg, 
-                                void *last_fg,
-                                int *has_bg, int *has_fg);
-
-#if 0
-#define VNC_MAX_WIDTH 2048
-#define VNC_MAX_HEIGHT 2048
-#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
-#endif
-
-#define VNC_AUTH_CHALLENGE_SIZE 16
-
-enum {
-    VNC_AUTH_INVALID = 0,
-    VNC_AUTH_NONE = 1,
-    VNC_AUTH_VNC = 2,
-    VNC_AUTH_RA2 = 5,
-    VNC_AUTH_RA2NE = 6,
-    VNC_AUTH_TIGHT = 16,
-    VNC_AUTH_ULTRA = 17,
-    VNC_AUTH_TLS = 18,
-    VNC_AUTH_VENCRYPT = 19
-};
-
 #ifdef CONFIG_VNC_TLS
 enum {
     VNC_WIREMODE_CLEAR,
     VNC_WIREMODE_TLS,
 };
-
-enum {
-    VNC_AUTH_VENCRYPT_PLAIN = 256,
-    VNC_AUTH_VENCRYPT_TLSNONE = 257,
-    VNC_AUTH_VENCRYPT_TLSVNC = 258,
-    VNC_AUTH_VENCRYPT_TLSPLAIN = 259,
-    VNC_AUTH_VENCRYPT_X509NONE = 260,
-    VNC_AUTH_VENCRYPT_X509VNC = 261,
-    VNC_AUTH_VENCRYPT_X509PLAIN = 262,
-};
-
-#define X509_CA_CERT_FILE "ca-cert.pem"
-#define X509_CA_CRL_FILE "ca-crl.pem"
-#define X509_SERVER_KEY_FILE "server-key.pem"
-#define X509_SERVER_CERT_FILE "server-cert.pem"
-
 #endif /* CONFIG_VNC_TLS */
 
-#define QUEUE_ALLOC_UNIT 10
-
-typedef struct _QueueItem
-{
-    int x, y, w, h;
-    int32_t enc;
-    struct _QueueItem *next;
-} QueueItem;
-
-typedef struct _Queue
-{
-    QueueItem *queue_start;
-    int start_count;
-    QueueItem *queue_end;
-    int end_count;
-} Queue;
-
-struct VncState
-{
-    QEMUTimer *timer;
-    int timer_interval;
-    int64_t last_update_time;
-    int lsock;
-    int csock;
-    DisplayState *ds;
-    uint64_t *dirty_row;	/* screen regions which are possibly dirty */
-    int dirty_pixel_shift;
-    uint64_t *update_row;	/* outstanding updates */
-    int has_update;		/* there's outstanding updates in the
-				 * visible area */
-
-    int update_requested;       /* the client requested an update */
-
-    uint8_t *old_data;
-    int has_resize;
-    int has_hextile;
-    int has_pointer_type_change;
-    int has_WMVi;
-    int absolute;
-    int last_x;
-    int last_y;
-
-    int major;
-    int minor;
-
-    char *display;
-    char *password;
-    int auth;
-#ifdef CONFIG_VNC_TLS
-    int subauth;
-    int x509verify;
-
-    char *x509cacert;
-    char *x509cacrl;
-    char *x509cert;
-    char *x509key;
-#endif
-    char challenge[VNC_AUTH_CHALLENGE_SIZE];
-    int switchbpp;
-
-#ifdef CONFIG_VNC_TLS
-    int wiremode;
-    gnutls_session_t tls_session;
-#endif
-
-    Buffer output;
-    Buffer input;
-    
-    Queue upqueue;
-
-    kbd_layout_t *kbd_layout;
-    /* current output mode information */
-    VncWritePixels *write_pixels;
-    VncSendHextileTile *send_hextile_tile;
-    DisplaySurface clientds, serverds;
-
-    VncReadEvent *read_handler;
-    size_t read_handler_expect;
-
-    int visible_x;
-    int visible_y;
-    int visible_w;
-    int visible_h;
-
-    /* input */
-    uint8_t modifiers_state[256];
-};
-
-static VncState *vnc_state; /* needed for info vnc */
 static DisplayChangeListener *dcl;
 
 #define DIRTY_PIXEL_BITS 64
@@ -263,15 +103,10 @@ void do_info_vnc(void)
    3) resolutions > 1024
 */
 
-static void vnc_write(VncState *vs, const void *data, size_t len);
-static void vnc_write_u32(VncState *vs, uint32_t value);
 static void vnc_write_s32(VncState *vs, int32_t value);
 static void vnc_write_u16(VncState *vs, uint16_t value);
-static void vnc_write_u8(VncState *vs, uint8_t value);
-static void vnc_flush(VncState *vs);
 static void _vnc_update_client(void *opaque);
 static void vnc_update_client(void *opaque);
-static void vnc_client_read(void *opaque);
 static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h);
 static void pixel_format_message (VncState *vs);
 static void enqueue_framebuffer_update(VncState *vs, int x, int y, int w, int h, int32_t encoding);
@@ -781,7 +616,7 @@ static int vnc_listen_poll(void *opaque)
     return 0;
 }
 
-static void buffer_reserve(Buffer *buffer, size_t len)
+void buffer_reserve(Buffer *buffer, size_t len)
 {
     if ((buffer->capacity - buffer->offset) < len) {
 	buffer->capacity += (len + 1024);
@@ -808,12 +643,19 @@ static void buffer_reset(Buffer *buffer)
     buffer->offset = 0;
 }
 
-static void buffer_append(Buffer *buffer, const void *data, size_t len)
+void buffer_append(Buffer *buffer, const void *data, size_t len)
 {
     memcpy(buffer->buffer + buffer->offset, data, len);
     buffer->offset += len;
 }
 
+static void buffer_advance(Buffer *buf, size_t len)
+{
+    memmove(buf->buffer, buf->buffer + len,
+            (buf->offset - len));
+    buf->offset -= len;
+}
+
 static void enqueue_framebuffer_update(VncState *vs, int x, int y, int w, int h,
                                    int32_t encoding)
 {
@@ -896,7 +738,7 @@ static void free_queue(VncState *vs)
     q->end_count = 0;
 }
 
-static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
+int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 {
     if (ret == 0 || ret == -1) {
         if (ret == -1) {
@@ -933,7 +775,7 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
     return ret;
 }
 
-static void vnc_client_error(VncState *vs)
+void vnc_client_error(VncState *vs)
 {
     vnc_client_io_error(vs, -1, EINVAL);
 }
@@ -960,9 +802,7 @@ static void vnc_client_write(void *opaque)
     if (!ret)
 	return;
 
-    memmove(vs->output.buffer, vs->output.buffer + ret,
-	    vs->output.offset - ret);
-    vs->output.offset -= ret;
+    buffer_advance(&vs->output, ret);
 
     if (vs->output.offset == 0)
 	qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
@@ -974,7 +814,7 @@ static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
     vs->read_handler_expect = expecting;
 }
 
-static void vnc_client_read(void *opaque)
+void vnc_client_read(void *opaque)
 {
     VncState *vs = opaque;
     long ret;
@@ -1009,9 +849,7 @@ static void vnc_client_read(void *opaque)
 	    return;
 
 	if (!ret) {
-	    memmove(vs->input.buffer, vs->input.buffer + len,
-		    vs->input.offset - len);
-	    vs->input.offset -= len;
+            buffer_advance(&vs->input, len);
 	} else {
 	    assert(ret > vs->read_handler_expect);
 	    vs->read_handler_expect = ret;
@@ -1019,7 +857,7 @@ static void vnc_client_read(void *opaque)
     }
 }
 
-static void vnc_write(VncState *vs, const void *data, size_t len)
+void vnc_write(VncState *vs, const void *data, size_t len)
 {
     buffer_reserve(&vs->output, len);
 
@@ -1035,7 +873,7 @@ static void vnc_write_s32(VncState *vs, int32_t value)
     vnc_write_u32(vs, *(uint32_t *)&value);
 }
 
-static void vnc_write_u32(VncState *vs, uint32_t value)
+void vnc_write_u32(VncState *vs, uint32_t value)
 {
     uint8_t buf[4];
 
@@ -1057,12 +895,12 @@ static void vnc_write_u16(VncState *vs, uint16_t value)
     vnc_write(vs, buf, 2);
 }
 
-static void vnc_write_u8(VncState *vs, uint8_t value)
+void vnc_write_u8(VncState *vs, uint8_t value)
 {
     vnc_write(vs, &value, 1);
 }
 
-static void vnc_flush(VncState *vs)
+void vnc_flush(VncState *vs)
 {
     if (vs->output.offset)
 	vnc_client_write(vs);
@@ -1084,7 +922,7 @@ static int32_t read_s32(uint8_t *data, size_t offset)
 		     (data[offset + 2] << 8) | data[offset + 3]);
 }
 
-static uint32_t read_u32(uint8_t *data, size_t offset)
+uint32_t read_u32(uint8_t *data, size_t offset)
 {
     return ((data[offset] << 24) | (data[offset + 1] << 16) |
 	    (data[offset + 2] << 8) | data[offset + 3]);
@@ -1788,6 +1626,10 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
     return 0;
 }
 
+void start_client_init(VncState *vs)
+{
+    vnc_read_when(vs, protocol_client_init, 1);
+}
 
 static void make_challenge(VncState *vs)
 {
@@ -1844,7 +1686,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
 	vnc_write_u32(vs, 0); /* Accept auth */
 	vnc_flush(vs);
 
-	vnc_read_when(vs, protocol_client_init, 1);
+	start_client_init(vs);
     }
     return 0;
 }
@@ -2317,7 +2159,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
                vnc_write_u32(vs, 0); /* Accept auth completion */
                vnc_flush(vs);
            }
-           vnc_read_when(vs, protocol_client_init, 1);
+           start_client_init(vs);
            break;
 
        case VNC_AUTH_VNC:
@@ -2380,7 +2222,7 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
             VNC_DEBUG("Tell client auth none\n");
             vnc_write_u32(vs, vs->auth);
             vnc_flush(vs);
-            vnc_read_when(vs, protocol_client_init, 1);
+            start_client_init(vs);
        } else if (vs->auth == VNC_AUTH_VNC) {
             VNC_DEBUG("Tell client VNC auth\n");
             vnc_write_u32(vs, vs->auth);
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH RFC 5/6] qemu-xen-trad: sasl: introduce SASL authentication and encryption layer
  2017-05-15 23:03 [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC Simon Waterman
                   ` (3 preceding siblings ...)
  2017-05-15 23:03 ` [PATCH RFC 4/6] qemu-xen-trad: sasl: compatibility with vnc.h Simon Waterman
@ 2017-05-15 23:03 ` Simon Waterman
  2017-05-15 23:03 ` [PATCH RFC 6/6] qemu-xen-trad: sasl: add SASL option at build time Simon Waterman
  2017-05-16 13:11 ` [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC George Dunlap
  6 siblings, 0 replies; 13+ messages in thread
From: Simon Waterman @ 2017-05-15 23:03 UTC (permalink / raw)
  To: xen-devel; +Cc: dunlapg, ian.jackson, Simon Waterman

This change adds calls to the SASL API to negotiate SASL auth and
includes SASL encode/decode into read and write flows if the SASL
mechanism is providing SSF.

The code is taken from upstream with minor adjustments for
compatibility with qemu-xen-traditional.

Signed-off-by: Simon Waterman <watermansrdev@gmail.com>
---
 vnc.c | 329 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 292 insertions(+), 37 deletions(-)

diff --git a/vnc.c b/vnc.c
index 728efec..ff460b8 100644
--- a/vnc.c
+++ b/vnc.c
@@ -80,6 +80,58 @@ static DisplayChangeListener *dcl;
   (((x) + (1ULL << (vs)->dirty_pixel_shift) - 1) >> (vs)->dirty_pixel_shift)
 #define DP2X(vs, x) ((x) << (vs)->dirty_pixel_shift)
 
+#ifndef CONFIG_STUBDOM
+static char *addr_to_string(const char *format,
+                            struct sockaddr_storage *sa,
+                            socklen_t salen) {
+    char *addr;
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    int err;
+    size_t addrlen;
+
+    if ((err = getnameinfo((struct sockaddr *)sa, salen,
+                           host, sizeof(host),
+                           serv, sizeof(serv),
+                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+        VNC_DEBUG("Cannot resolve address %d: %s\n",
+                  err, gai_strerror(err));
+        return NULL;
+    }
+
+    /* Enough for the existing format + the 2 vars we're
+     * substituting in. */
+    addrlen = strlen(format) + strlen(host) + strlen(serv);
+    addr = malloc(addrlen + 1);
+    snprintf(addr, addrlen, format, host, serv);
+    addr[addrlen] = '\0';
+
+    return addr;
+}
+
+char *vnc_socket_local_addr(const char *format, int fd) {
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa, salen);
+}
+
+char *vnc_socket_remote_addr(const char *format, int fd) {
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa, salen);
+}
+#endif /* !CONFIG_STUBDOM */
+
 void do_info_vnc(void)
 {
     if (vnc_state == NULL)
@@ -770,6 +822,9 @@ int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 	}
 	vs->wiremode = VNC_WIREMODE_CLEAR;
 #endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+        vnc_sasl_client_cleanup(vs);
+#endif /* CONFIG_VNC_SASL */
 	return 0;
     }
     return ret;
@@ -780,65 +835,203 @@ void vnc_client_error(VncState *vs)
     vnc_client_io_error(vs, -1, EINVAL);
 }
 
-static void vnc_client_write(void *opaque)
+#ifdef CONFIG_VNC_TLS
+static long vnc_client_write_tls(gnutls_session_t *session,
+                                 const uint8_t *data,
+                                 size_t datalen)
+{
+    long ret = gnutls_write(*session, data, datalen);
+    if (ret < 0) { 
+        if (ret == GNUTLS_E_AGAIN) {
+            errno = EAGAIN;
+        } else {
+            errno = EIO;
+        }
+        ret = -1;
+    }
+    return ret;
+}
+#endif /* CONFIG_VNC_TLS */
+
+/*
+ * Called to write a chunk of data to the client socket. The data may
+ * be the raw data, or may have already been encoded by SASL.
+ * The data will be written either straight onto the socket, or
+ * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes written, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
 {
     long ret;
-    VncState *vs = opaque;
-
 #ifdef CONFIG_VNC_TLS
     if (vs->tls_session) {
-	ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset);
-	if (ret < 0) {
-	    if (ret == GNUTLS_E_AGAIN)
-		errno = EAGAIN;
-	    else
-		errno = EIO;
-	    ret = -1;
-	}
-    } else
+        ret = vnc_client_write_tls(&vs->tls_session, data, datalen);
+    } else {
+#endif /* CONFIG_VNC_TLS */
+        ret = send(vs->csock, data, datalen, 0);
+#ifdef CONFIG_VNC_TLS
+    }
 #endif /* CONFIG_VNC_TLS */
-	ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
-    ret = vnc_client_io_error(vs, ret, socket_error());
+    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
+
+/*
+ * Called to write buffered data to the client socket, when not
+ * using any SASL SSF encryption layers. Will write as much data
+ * as possible without blocking. If all buffered data is written,
+ * will switch the FD poll() handler back to read monitoring.
+ *
+ * Returns the number of bytes written, which may be less than
+ * the buffered output data if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+static long vnc_client_write_plain(VncState *vs)
+{
+    long ret;
+
+#ifdef CONFIG_VNC_SASL
+    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
+              vs->output.buffer, vs->output.capacity, vs->output.offset,
+              vs->sasl.waitWriteSSF);
+
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        vs->sasl.waitWriteSSF) {
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
+        if (ret)
+            vs->sasl.waitWriteSSF -= ret;
+    } else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
     if (!ret)
-	return;
+        return 0;
 
     buffer_advance(&vs->output, ret);
 
-    if (vs->output.offset == 0)
-	qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    if (vs->output.offset == 0) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    }
+
+    return ret;
 }
 
-static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
+/*
+ * First function called whenever there is data to be written to
+ * the client socket. Will delegate actual work according to whether
+ * SASL SSF layers are enabled (thus requiring encryption calls)
+ */
+static void vnc_client_write(void *opaque)
+{
+    long ret;
+    VncState *vs = opaque;
+
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        !vs->sasl.waitWriteSSF)
+        ret = vnc_client_write_sasl(vs);
+    else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_write_plain(vs);
+}
+
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
 {
     vs->read_handler = func;
     vs->read_handler_expect = expecting;
 }
 
-void vnc_client_read(void *opaque)
+#ifdef CONFIG_VNC_TLS
+static long vnc_client_read_tls(gnutls_session_t *session, uint8_t *data,
+                                size_t datalen)
 {
-    VncState *vs = opaque;
-    long ret;
-
-    buffer_reserve(&vs->input, 4096);
+    long ret = gnutls_read(*session, data, datalen);
+    if (ret < 0) { 
+        if (ret == GNUTLS_E_AGAIN) {
+            errno = EAGAIN;
+        } else {
+            errno = EIO;
+        }
+        ret = -1;
+    }
+    return ret;
+}
+#endif /* CONFIG_VNC_TLS */
 
+/*
+ * Called to read a chunk of data from the client socket. The data may
+ * be the raw data, or may need to be further decoded by SASL.
+ * The data will be read either straight from to the socket, or
+ * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes read, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
+{
+    long ret;
 #ifdef CONFIG_VNC_TLS
     if (vs->tls_session) {
-	ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096);
-	if (ret < 0) {
-	    if (ret == GNUTLS_E_AGAIN)
-		errno = EAGAIN;
-	    else
-		errno = EIO;
-	    ret = -1;
-	}
-    } else
+        ret = vnc_client_read_tls(&vs->tls_session, data, datalen);
+    } else {
 #endif /* CONFIG_VNC_TLS */
-	ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
-    ret = vnc_client_io_error(vs, ret, socket_error());
-    if (!ret)
-	return;
+        ret = recv(vs->csock, data, datalen, 0);
+#ifdef CONFIG_VNC_TLS
+    }
+#endif /* CONFIG_VNC_TLS */
+    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
 
+/*
+ * Called to read data from the client socket to the input buffer,
+ * when not using any SASL SSF encryption layers. Will read as much
+ * data as possible without blocking.
+ *
+ * Returns the number of bytes read. Returns -1 on error, and
+ * disconnects the client socket.
+ */
+static long vnc_client_read_plain(VncState *vs)
+{
+    int ret;
+    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
+              vs->input.buffer, vs->input.capacity, vs->input.offset);
+    buffer_reserve(&vs->input, 4096);
+    ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
+    if (!ret)
+        return 0;
     vs->input.offset += ret;
+    return ret;
+}
+
+void vnc_client_read(void *opaque)
+{
+    VncState *vs = opaque;
+    long ret;
+
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn && vs->sasl.runSSF)
+        ret = vnc_client_read_sasl(vs);
+    else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_read_plain(vs);
+    if (!ret)
+        return;
 
     while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
 	size_t len = vs->read_handler_expect;
@@ -1897,6 +2090,14 @@ static int start_auth_vencrypt_subauth(VncState *vs)
        VNC_DEBUG("Start TLS auth VNC\n");
        return start_auth_vnc(vs);
 
+#ifdef CONFIG_VNC_SASL
+    case VNC_AUTH_VENCRYPT_X509SASL:
+    case VNC_AUTH_VENCRYPT_TLSSASL:
+       VNC_DEBUG("Start TLS auth SASL\n");
+       start_auth_sasl(vs);
+    break;
+#endif /* CONFIG_VNC_SASL */
+
     default: /* Should not be possible, but just in case */
        VNC_DEBUG("Reject auth %d\n", vs->auth);
        vnc_write_u8(vs, 1);
@@ -1957,7 +2158,9 @@ static void vnc_handshake_io(void *opaque) {
 #define NEED_X509_AUTH(vs)			      \
     ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
      (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN || \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509SASL ||   \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_TLSSASL)
 
 #if defined(GNUTLS_VERSION_NUMBER) && \
     GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */
@@ -2172,6 +2375,13 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
            return start_auth_vencrypt(vs);
 #endif /* CONFIG_VNC_TLS */
 
+#ifdef CONFIG_VNC_SASL
+       case VNC_AUTH_SASL:
+           VNC_DEBUG("Accept SASL auth\n");
+           start_auth_sasl(vs);
+           break;
+#endif /* CONFIG_VNC_SASL */
+
        default: /* Should not be possible, but just in case */
            VNC_DEBUG("Reject auth %d\n", vs->auth);
            vnc_write_u8(vs, 1);
@@ -2435,6 +2645,10 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused)
 #ifdef CONFIG_VNC_TLS
     int tls = 0, x509 = 0;
 #endif
+    bool sasl = false;
+#ifdef CONFIG_VNC_SASL
+    int saslErr;
+#endif
 
     if (display == NULL)
 	display = "localhost:0";
@@ -2453,6 +2667,15 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused)
 	    password = 1; /* Require password auth */
         } else if (strncmp(options, "switchbpp", 9) == 0) {
             vs->switchbpp = 1;
+	} else if (strncmp(options, "sasl", 4) == 0) {
+#ifdef CONFIG_VNC_SASL
+	    sasl = 1; /* Require SASL auth */
+#else
+	    fprintf(stderr, "VNC SASL auth requires cyrus-sasl support\n");
+	    qemu_free(vs->display);
+	    vs->display = NULL;
+	    return -1;
+#endif /* CONFIG_VNC_SASL */
 #ifdef CONFIG_VNC_TLS
 	} else if (strncmp(options, "tls", 3) == 0) {
 	    tls = 1; /* Require TLS */
@@ -2509,6 +2732,27 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused)
 	    vs->subauth = VNC_AUTH_INVALID;
 	}
 #endif
+#ifdef CONFIG_VNC_SASL
+    } else if (sasl) {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+		VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
+            } else {
+		VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
+            }
+        } else {
+#endif /* CONFIG_VNC_TLS */
+	    VNC_DEBUG("Initializing VNC server with SASL auth\n");
+            vs->auth = VNC_AUTH_SASL;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif /* CONFIG_VNC_TLS */
+#endif /* CONFIG_VNC_SASL */
     } else {
 #ifdef CONFIG_VNC_TLS
 	if (tls) {
@@ -2529,6 +2773,17 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused)
 	}
 #endif
     }
+
+#ifdef CONFIG_VNC_SASL
+    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
+        fprintf(stderr, "Failed to initialize SASL auth %s",
+                sasl_errstring(saslErr, NULL, NULL));
+        free(vs->display);
+        vs->display = NULL;
+        return -1;
+    }
+#endif
+
 #ifndef NO_UNIX_SOCKETS
     if (strstart(display, "unix:", &p)) {
 	addr = (struct sockaddr *)&uaddr;
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH RFC 6/6] qemu-xen-trad: sasl: add SASL option at build time
  2017-05-15 23:03 [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC Simon Waterman
                   ` (4 preceding siblings ...)
  2017-05-15 23:03 ` [PATCH RFC 5/6] qemu-xen-trad: sasl: introduce SASL authentication and encryption layer Simon Waterman
@ 2017-05-15 23:03 ` Simon Waterman
  2017-05-16 13:11 ` [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC George Dunlap
  6 siblings, 0 replies; 13+ messages in thread
From: Simon Waterman @ 2017-05-15 23:03 UTC (permalink / raw)
  To: xen-devel; +Cc: dunlapg, ian.jackson, Simon Waterman

This change adds build support for the SASL integration,
disabled by default.

Signed-off-by: Simon Waterman <watermansrdev@gmail.com>
---
 Makefile.target |  6 ++++++
 configure       | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/Makefile.target b/Makefile.target
index 3c3db2b..a225a30 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -557,6 +557,12 @@ CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
 LIBS += $(CONFIG_VNC_TLS_LIBS)
 endif
 
+ifdef CONFIG_VNC_SASL
+CPPFLAGS += $(CONFIG_VNC_SASL_CFLAGS)
+LIBS += $(CONFIG_VNC_SASL_LIBS)
+OBJS+= vnc-auth-sasl.o
+endif
+
 ifdef CONFIG_BLUEZ
 LIBS += $(CONFIG_BLUEZ_LIBS)
 endif
diff --git a/configure b/configure
index 4547359..b2e9b79 100755
--- a/configure
+++ b/configure
@@ -164,6 +164,7 @@ fmod_lib=""
 fmod_inc=""
 oss_lib=""
 vnc_tls="yes"
+vnc_sasl="no"
 bsd="no"
 linux="no"
 solaris="no"
@@ -390,6 +391,8 @@ for opt do
   ;;
   --disable-vnc-tls) vnc_tls="no"
   ;;
+  --enable-vnc-sasl) vnc_sasl="yes"
+  ;;
   --disable-slirp) slirp="no"
   ;;
   --disable-vde) vde="no"
@@ -548,6 +551,7 @@ echo "                           Available cards: $audio_possible_cards"
 echo "  --enable-mixemu          enable mixer emulation"
 echo "  --disable-brlapi         disable BrlAPI"
 echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
+echo "  --enable-vnc-sasl        enable SASL encryption for VNC server"
 echo "  --disable-curses         disable curses output"
 echo "  --disable-bluez          disable bluez stack connectivity"
 echo "  --disable-kvm            disable KVM acceleration support"
@@ -842,6 +846,25 @@ EOF
 fi
 
 ##########################################
+# VNC SASL detection
+if test "$vnc_sasl" = "yes" ; then
+cat > $TMPC <<EOF
+#include <sasl/sasl.h>
+#include <stdio.h>
+int main(void) { sasl_server_init(NULL, "qemu"); return 0; }
+EOF
+    # Assuming Cyrus-SASL installed in /usr prefix
+    vnc_sasl_cflags=""
+    vnc_sasl_libs="-lsasl2"
+    if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $vnc_sasl_cflags $TMPC \
+           $vnc_sasl_libs 2> /dev/null ; then
+	:
+    else
+	vnc_sasl="no"
+    fi
+fi
+
+##########################################
 # vde libraries probe
 if test "$vde" = "yes" ; then
   cat > $TMPC << EOF
@@ -1169,6 +1192,11 @@ if test "$vnc_tls" = "yes" ; then
     echo "    TLS CFLAGS    $vnc_tls_cflags"
     echo "    TLS LIBS      $vnc_tls_libs"
 fi
+echo "VNC SASL support  $vnc_sasl"
+if test "$vnc_sasl" = "yes" ; then
+    echo "    SASL CFLAGS    $vnc_sasl_cflags"
+    echo "    SASL LIBS      $vnc_sasl_libs"
+fi
 if test -n "$sparc_cpu"; then
     echo "Target Sparc Arch $sparc_cpu"
 fi
@@ -1414,6 +1442,12 @@ if test "$vnc_tls" = "yes" ; then
   echo "CONFIG_VNC_TLS_LIBS=$vnc_tls_libs" >> $config_mak
   echo "#define CONFIG_VNC_TLS 1" >> $config_h
 fi
+if test "$vnc_sasl" = "yes" ; then
+  echo "CONFIG_VNC_SASL=yes" >> $config_mak
+  echo "CONFIG_VNC_SASL_CFLAGS=$vnc_sasl_cflags" >> $config_mak
+  echo "CONFIG_VNC_SASL_LIBS=$vnc_sasl_libs" >> $config_mak
+  echo "#define CONFIG_VNC_SASL 1" >> $config_h
+fi
 qemu_version=`head $source_path/VERSION`
 echo "VERSION=$qemu_version" >>$config_mak
 echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC
  2017-05-15 23:03 [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC Simon Waterman
                   ` (5 preceding siblings ...)
  2017-05-15 23:03 ` [PATCH RFC 6/6] qemu-xen-trad: sasl: add SASL option at build time Simon Waterman
@ 2017-05-16 13:11 ` George Dunlap
  2017-05-16 13:16   ` Ian Jackson
  6 siblings, 1 reply; 13+ messages in thread
From: George Dunlap @ 2017-05-16 13:11 UTC (permalink / raw)
  To: Simon Waterman; +Cc: Ian Jackson, xen-devel

On Tue, May 16, 2017 at 12:03 AM, Simon Waterman
<watermansrdev@gmail.com> wrote:
> This patch series back-ports SASL authentication from
> upstream QEMU to the VNC server in qemu-xen-traditional.
> It enables authentication to the VNC console of a domain
> to be controlled using any SASL mechanism when using an
> IOEMU stubdom.
>
> SASL can be used with or without X509 certificates.
>
> The option is currently enabled during build by adding
> --enable-vnc-sasl to the configure line in xen-setup in the
> root of the QEMU tree.
>
> SASL auth can be enabled for a domain using the 'vnclisten'
> option in the Xen config file:
> vnclisten="0.0.0.0:5,tls,x509verify=/etc/ssl,sasl"
>
> Details of how to configure SASL in QEMU can be found here:
> https://qemu.weilnetz.de/doc/qemu-doc.html#vnc_005fsec_005fsasl

Hmm, I don't think this counts as "small patch with simple changes",
but I'll let Ian comment.

 -George

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC
  2017-05-16 13:11 ` [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC George Dunlap
@ 2017-05-16 13:16   ` Ian Jackson
  2017-05-16 13:19     ` George Dunlap
  0 siblings, 1 reply; 13+ messages in thread
From: Ian Jackson @ 2017-05-16 13:16 UTC (permalink / raw)
  To: George Dunlap; +Cc: Simon Waterman, xen-devel

George Dunlap writes ("Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC"):
> Hmm, I don't think this counts as "small patch with simple changes",
> but I'll let Ian comment.

I'm quite uneasy about this.  It seems like the addition of a lot of
code; effectively, a fork of the SASL code from upstream.

Presumably the real end goal here is something to do with security.
But I don't think we would want to offer security support for this new
functionality.

And it might complicate other fixes to qemu-trad, because different
versions of qemu-trad would need different patches (ie, it might
complicate backporting existing securit fixes).

Simon: What is stopping you moving to a modern version of qemu ?

Regards,
Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC
  2017-05-16 13:16   ` Ian Jackson
@ 2017-05-16 13:19     ` George Dunlap
  2017-05-16 13:28       ` Ian Jackson
  0 siblings, 1 reply; 13+ messages in thread
From: George Dunlap @ 2017-05-16 13:19 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Simon Waterman, xen-devel

On 16/05/17 14:16, Ian Jackson wrote:
> George Dunlap writes ("Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC"):
>> Hmm, I don't think this counts as "small patch with simple changes",
>> but I'll let Ian comment.
> 
> I'm quite uneasy about this.  It seems like the addition of a lot of
> code; effectively, a fork of the SASL code from upstream.
> 
> Presumably the real end goal here is something to do with security.
> But I don't think we would want to offer security support for this new
> functionality.
> 
> And it might complicate other fixes to qemu-trad, because different
> versions of qemu-trad would need different patches (ie, it might
> complicate backporting existing securit fixes).
> 
> Simon: What is stopping you moving to a modern version of qemu ?

I think from his previous query, it was the fact that there is no
suitable stubdom for qemu-upstream.

 -George


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC
  2017-05-16 13:19     ` George Dunlap
@ 2017-05-16 13:28       ` Ian Jackson
  2017-05-17 18:49         ` Simon Waterman
  0 siblings, 1 reply; 13+ messages in thread
From: Ian Jackson @ 2017-05-16 13:28 UTC (permalink / raw)
  To: George Dunlap; +Cc: Simon Waterman, xen-devel

George Dunlap writes ("Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC"):
> On 16/05/17 14:16, Ian Jackson wrote:
> > Simon: What is stopping you moving to a modern version of qemu ?
> 
> I think from his previous query, it was the fact that there is no
> suitable stubdom for qemu-upstream.

Hrm.  I think fixing this is probably a better approach.  Although it
seems likely to be more involved, it would have better overall
viability.  Another stopgap would be to use a proxy somewhere to do
the SASL etc.

Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC
  2017-05-16 13:28       ` Ian Jackson
@ 2017-05-17 18:49         ` Simon Waterman
  2017-05-18 14:43           ` Ian Jackson
  0 siblings, 1 reply; 13+ messages in thread
From: Simon Waterman @ 2017-05-17 18:49 UTC (permalink / raw)
  To: Ian Jackson, George Dunlap; +Cc: xen-devel



On 16/05/17 14:28, Ian Jackson wrote:
> George Dunlap writes ("Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC"):
>> On 16/05/17 14:16, Ian Jackson wrote:
>>> Simon: What is stopping you moving to a modern version of qemu ?
>> I think from his previous query, it was the fact that there is no
>> suitable stubdom for qemu-upstream.
> Hrm.  I think fixing this is probably a better approach.  Although it
> seems likely to be more involved, it would have better overall
> viability.  Another stopgap would be to use a proxy somewhere to do
> the SASL etc.
>
> Ian.
It's not the QEMU in the stubdom that would need to be newer
but rather the one that's spawned in domain-0 to provide the
VNC backend when you use an IOEMU stubdom.  As I understand
it this also needs to be qemu-xen-traditional but maybe
I've got that wrong?

I agree entirely that enabling upstream QEMU to be used
here would be a better approach and that might be easier
than getting it running inside the stubdom itself.

Maybe I could look into that if it's not already supported.

The port itself is pretty simple.  The biggest change is
probably the refactor of definitions into the header.  I
think it should be relatively easy to verify it's
correctness but I get the point about maintenance of
older versions of qemu-xen-traditional needing different
patches if there was a vulnerability in QEMU VNC.

I think it would be nice to have a better set of options
for authenticating VNC than a fixed shared password and
with SASL you can do GSSAPI, LDAP and a host of others.

To be honest I'm not sure how much it would be used generally.
You can get most of the same benefits using an SSH tunnel
but then again you've got to get that config correct to
keep your domain-0 secure and the client setup is a bit
more fiddly.

In it's favour, there are quite a few VNC clients with
SASL support built-in including virt-viewer and anything
based upon gtk-vnc.  I submitted a patch to libvncserver
so that it's available in Guacamole too.

Has any thought been put into running the VNC server in
the stubdom itself?  That might be nice as VNC access
would be possible without access to the domain-0 at all.
It might help with the 'rebootable' domain-0 work too as
VNC connections wouldn't drop when the domain-0 is restarted.

Thanks for considering the patch, whether it goes in
or not.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC
  2017-05-17 18:49         ` Simon Waterman
@ 2017-05-18 14:43           ` Ian Jackson
  0 siblings, 0 replies; 13+ messages in thread
From: Ian Jackson @ 2017-05-18 14:43 UTC (permalink / raw)
  To: Simon Waterman; +Cc: George Dunlap, xen-devel

Simon Waterman writes ("Re: [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC"):
> It's not the QEMU in the stubdom that would need to be newer
> but rather the one that's spawned in domain-0 to provide the
> VNC backend when you use an IOEMU stubdom.  As I understand
> it this also needs to be qemu-xen-traditional but maybe
> I've got that wrong?

No, I don't think it does.

> I agree entirely that enabling upstream QEMU to be used
> here would be a better approach and that might be easier
> than getting it running inside the stubdom itself.

Yes.

> Maybe I could look into that if it's not already supported.

Please do!  The relevant code is in libxl and shouldn't be too hard to
find.

I think it would probably be right to just unconditionally use
qemu-xen rather than trad for the PV backend qemu.

> Has any thought been put into running the VNC server in
> the stubdom itself?  That might be nice as VNC access
> would be possible without access to the domain-0 at all.
> It might help with the 'rebootable' domain-0 work too as
> VNC connections wouldn't drop when the domain-0 is restarted.

I think if we had upstream qemu stubdomains, we would probably be able
to do something like this.

Regards,
Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2017-05-18 14:43 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-15 23:03 [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC Simon Waterman
2017-05-15 23:03 ` [PATCH RFC 1/6] qemu-xen-trad: sasl: expose vnc API to SASL auth Simon Waterman
2017-05-15 23:03 ` [PATCH RFC 2/6] qemu-xen-trad: sasl: define SASL auth API Simon Waterman
2017-05-15 23:03 ` [PATCH RFC 3/6] qemu-xen-trad: sasl: implement SASL auth Simon Waterman
2017-05-15 23:03 ` [PATCH RFC 4/6] qemu-xen-trad: sasl: compatibility with vnc.h Simon Waterman
2017-05-15 23:03 ` [PATCH RFC 5/6] qemu-xen-trad: sasl: introduce SASL authentication and encryption layer Simon Waterman
2017-05-15 23:03 ` [PATCH RFC 6/6] qemu-xen-trad: sasl: add SASL option at build time Simon Waterman
2017-05-16 13:11 ` [PATCH RFC 0/6] qemu-xen-trad: sasl: add SASL support to VNC George Dunlap
2017-05-16 13:16   ` Ian Jackson
2017-05-16 13:19     ` George Dunlap
2017-05-16 13:28       ` Ian Jackson
2017-05-17 18:49         ` Simon Waterman
2017-05-18 14:43           ` Ian Jackson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.