From: Anthony Liguori <anthony@codemonkey.ws>
To: "Daniel P. Berrange" <berrange@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] PATCH: RFC: Support SASL authentication in VNC
Date: Wed, 04 Feb 2009 13:10:59 -0600 [thread overview]
Message-ID: <4989E843.5000004@codemonkey.ws> (raw)
In-Reply-To: <20090204171625.GI26946@redhat.com>
Hi Dan,
Daniel P. Berrange wrote:
> Previously I provided patches for QEMU's VNC server to support SSL/TLS
> and x509 certificates. This provides good encryption capabilities for
> the VNC session. It doesn't really address the authentication problem
> though.
>
> I have been working to create a new authentication type in the RFB
> protocol to address this need in a generic, extendable way, by mapping
> the SASL API into the RFB protocol. Since SASL is a generic plugin
> based API, this will allow use of a huge range of auth mechanims over
> VNC, without us having to add any more auth code. For example, PAM,
> Digest-MD5, GSSAPI/Kerberos, One-time key/password, LDAP password
> lookup, SQL db password lookup, and more.
>
> I have got a VNC auth type assigned by the RFB spec maintainers:
>
> http://realvnc.com/pipermail/vnc-list/2008-December/059463.html
>
> With the full current spec for the SASL extension currently documented
> here:
>
> http://realvnc.com/pipermail/vnc-list/2008-December/059462.html
>
> This patch provides an initial implementation of this extension for the
> QEMU VNC server. I am not requesting it is merged just yet, but I'd like
> get it all finished in time of the suggested QEMU release at the end
> of the month, so I'm sending the patch out now for early comments
>
> In most circumstances, it is neccessary to combine use of SASL, with
> the TLS + x509 support, since most SASL mechanisms only provide for
> authentication. In this case you would launch QEMU with
>
> qemu ... -vnc localhost:1,tls,x509,sasl
>
>
> The Kerberos GSSAPI mechanism for SASL is unusual in that it can also
> provide encryption of the data session (so called SSF layer in SASL
> terminology). If using this, QEMU can be launched with just
>
> qemu ... -vnc localhost:1,sasl
>
> The actual choice of SASL mechanism is controlled by the SASL service
> configuration file. THis patch integrates with Cyrus-SASL library and
> thus the config is in /etc/sasl2/qemu.conf. This patch does not yet
> support it, but I intend too add support for overriding this config
> with $HOME/.sasl2/qemu.conf, since most people use QEMU in their regular
> user accounts and may not have access to the system SASL configs. The
> updates to qemu-doc.texi show how to config SASL, or the Cyrus-SASL docs
> can be referred to.
>
> As I mentioned, this uses Cyrus-SASL libraries. The configure script
> probes for this, and disables SASL support if not found, so it should
> not cause problems for places without Cyrus-SASL like Windows.
>
> The main missing points in this patch
>
> - Authorization. Once we've authenticated the user, how do we
> decide whether they're allow to use VNC. eg, just because a
> user has a valid Kerberos principle, does not imply we should
> allow access.
>
> We really need an access control list, listing the allowed
> SASL usernames and/or x509 client certificate CNAMEs which
> are authorized. This should probably live in an external
> file, perhaps allowing for ACLs against multiple different
> QEMU network based devices. eg I could just add a arg
>
> -acl /path/to/aclfile
>
Not a huge fan of using an acl file but I'm not terribly opposed to it
either. I like the monitor commands but obviously, we'll need a
mechanism to list existing acls too.
> Makefile.target | 5
> configure | 34 ++
> qemu-doc.texi | 94 ++++++
> qemu.sasl | 34 ++
> vnc.c | 800 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> vnc.h | 16 -
> 6 files changed, 964 insertions(+), 19 deletions(-)
>
> Regards,
> Daniel
>
>
> Index: Makefile.target
> ===================================================================
> --- Makefile.target (revision 6511)
> +++ Makefile.target (working copy)
> @@ -554,6 +554,11 @@
> LIBS += $(CONFIG_VNC_TLS_LIBS)
> endif
>
> +ifdef CONFIG_VNC_SASL
> +CPPFLAGS += $(CONFIG_VNC_SASL_CFLAGS)
> +LIBS += $(CONFIG_VNC_SASL_LIBS)
> +endif
> +
> ifdef CONFIG_BLUEZ
> LIBS += $(CONFIG_BLUEZ_LIBS)
> endif
> Index: vnc.c
> ===================================================================
> --- vnc.c (revision 6511)
> +++ vnc.c (working copy)
> @@ -43,8 +43,12 @@
> #include <gnutls/x509.h>
> #endif /* CONFIG_VNC_TLS */
>
> -// #define _VNC_DEBUG 1
> +#ifdef CONFIG_VNC_SASL
> +#include <sasl/sasl.h>
> +#endif
>
> +#define _VNC_DEBUG 1
> +
> #ifdef _VNC_DEBUG
> #define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
>
> @@ -123,6 +127,32 @@
> char *x509cert;
> char *x509key;
> #endif
> +
> +#ifdef CONFIG_VNC_SASL
> + sasl_conn_t *saslconn;
> + /* If we want to negotiate an SSF layer with client */
> + int saslWantSSF :1;
> + /* If we are now running the SSF layer */
> + int saslRunSSF :1;
> + /*
> + * 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 saslWaitWriteSSF;
> +
> + /*
> + * Buffering encoded data to allow more clear data
> + * to be stuffed onto the output buffer
> + */
> + const uint8_t *saslEncoded;
> + unsigned int saslEncodedLength;
> + unsigned int saslEncodedOffset;
> + char *saslUsername;
> + char *saslMechlist;
> +#endif
>
I think we could use a little more love here that moved the sasl bits to
a vnc-sasl.c provide that it's a sane thing to do.
> +
> char challenge[VNC_AUTH_CHALLENGE_SIZE];
>
> #ifdef CONFIG_VNC_TLS
> @@ -829,6 +859,18 @@
> }
> vs->wiremode = VNC_WIREMODE_CLEAR;
> #endif /* CONFIG_VNC_TLS */
> +#ifdef CONFIG_VNC_SASL
> + if (vs->saslconn) {
> + vs->saslRunSSF = vs->saslWaitWriteSSF = vs->saslWantSSF = 0;
> + vs->saslEncodedLength = vs->saslEncodedOffset = 0;
> + vs->saslEncoded = NULL;
> + free(vs->saslUsername);
> + free(vs->saslMechlist);
> + vs->saslUsername = vs->saslMechlist = NULL;
> + sasl_dispose(&vs->saslconn);
> + vs->saslconn = NULL;
> + }
> +#endif /* CONFIG_VNC_SASL */
> audio_del(vs);
> return 0;
> }
> @@ -840,14 +882,12 @@
> vnc_client_io_error(vs, -1, EINVAL);
> }
>
> -static void vnc_client_write(void *opaque)
> +static long vnc_client_write_wire(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);
> + ret = gnutls_write(vs->tls_session, data, datalen);
> if (ret < 0) {
> if (ret == GNUTLS_E_AGAIN)
> errno = EAGAIN;
> @@ -857,35 +897,117 @@
> }
> } else
> #endif /* CONFIG_VNC_TLS */
> - ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
> - ret = vnc_client_io_error(vs, ret, socket_error());
> + ret = send(vs->csock, data, datalen, 0);
> + VNC_DEBUG("Wrote wire %p %d -> %ld\n", data, datalen, ret);
> + return vnc_client_io_error(vs, ret, socket_error());
> +}
>
These changes seem extraneous. I'll just assume the patch needs cleanup
for such things.
> +#ifdef CONFIG_VNC_SASL
> +static long vnc_client_write_sasl(VncState *vs)
> +{
> + long ret;
> +
> + VNC_DEBUG("Write SASL: Pending output %p size %d offset %d Encoded: %p size %d offset %d\n",
> + vs->output.buffer, vs->output.capacity, vs->output.offset,
> + vs->saslEncoded, vs->saslEncodedLength, vs->saslEncodedOffset);
> +
> + if (!vs->saslEncoded) {
> + int err;
> + err = sasl_encode(vs->saslconn,
> + (char *)vs->output.buffer,
> + vs->output.offset,
> + (const char **)&vs->saslEncoded,
> + &vs->saslEncodedLength);
> + if (err != SASL_OK)
> + return vnc_client_io_error(vs, -1, EIO);
> +
> + vs->output.offset = 0;
> + vs->saslEncodedOffset = 0;
> + }
> +
> + ret = vnc_client_write_wire(vs,
> + vs->saslEncoded + vs->saslEncodedOffset,
> + vs->saslEncodedLength - vs->saslEncodedOffset);
> if (!ret)
> - return;
> + return 0;
>
> + vs->saslEncodedOffset += ret;
> + if (vs->saslEncodedOffset == vs->saslEncodedLength) {
> + vs->saslEncoded = NULL;
> + vs->saslEncodedOffset = vs->saslEncodedLength = 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_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
> + }
> +
> + return ret;
> +}
> +#endif /* CONFIG_VNC_SASL */
> +
> +static long vnc_client_write_plain(VncState *vs)
> +{
> + long ret;
> +
> +#ifdef CONFIG_VNC_SASL
> + VNC_DEBUG("Write Plain: Pending output %p size %d offset %d. Wait SSF %d\n",
> + vs->output.buffer, vs->output.capacity, vs->output.offset,
> + vs->saslWaitWriteSSF);
> +
> + if (vs->saslconn &&
> + vs->saslRunSSF &&
> + vs->saslWaitWriteSSF) {
> + ret = vnc_client_write_wire(vs, vs->output.buffer, vs->saslWaitWriteSSF);
> + if (ret)
> + vs->saslWaitWriteSSF -= ret;
> + } else
> +#endif /* CONFIG_VNC_SASL */
> + ret = vnc_client_write_wire(vs, vs->output.buffer, vs->output.offset);
> + if (!ret)
> + return 0;
> +
> memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
> vs->output.offset -= ret;
>
> if (vs->output.offset == 0) {
> qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
> }
> +
> + return ret;
> }
>
So there are three possible layers of write interaction. SASL -> TLS ->
Socket. I think adding a mechanism to register write hooks to implement
SASL and TLS would be good. If you can, moving the TLS support into a
separate file would be helpful too.
>
> +#ifdef CONFIG_VNC_SASL
> +/* Max amount of data we send/recv for SASL steps to prevent DOS */
> +#define SASL_DATA_MAX_LEN (1024 * 1024)
Be careful with this. Kerberos tickets can contain arbitrary data (for
instance, the MS PAC). This can make the data transfer size be much
larger than you'd expect.
I like the general idea here. SASL is a nice mechanism and the
implementation is pretty straight forward. I'll do a more thorough
review when you get something closer to ready for inclusion.
Regards,
Anthony Liguori
next prev parent reply other threads:[~2009-02-04 19:11 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-02-04 17:16 [Qemu-devel] PATCH: RFC: Support SASL authentication in VNC Daniel P. Berrange
2009-02-04 19:10 ` Anthony Liguori [this message]
2009-02-04 22:47 ` Daniel P. Berrange
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4989E843.5000004@codemonkey.ws \
--to=anthony@codemonkey.ws \
--cc=berrange@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).