You can subscribe to this list here.
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(4) |
Jun
(7) |
Jul
(80) |
Aug
(61) |
Sep
(29) |
Oct
(59) |
Nov
(12) |
Dec
(53) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2008 |
Jan
(144) |
Feb
(117) |
Mar
(71) |
Apr
(117) |
May
(16) |
Jun
(21) |
Jul
(2) |
Aug
(8) |
Sep
(24) |
Oct
(50) |
Nov
(17) |
Dec
(50) |
2009 |
Jan
(3) |
Feb
(6) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Richard W.M. J. <rj...@re...> - 2010-07-01 19:41:59
|
As the error message says ... # virt-viewer RHEL6beta2x64 Xlib: extension "RANDR" missing on display "localhost:10.0". (virt-viewer:17347): gtk-vnc-WARNING **: unknown keycodes `empty_aliases(qwerty)', please report to gtk-vnc-devel So you'll probably want to know what X server this is, etc: The server is XQuartz 2.5.0 (xorg-server 1.7.6) on Mac OS X 10.5.8. The client is virt-viewer 0.2.0-1.fc12.x86_64 (gtk-vnc-0.3.10-1.fc12.x86_64). I notice these are a bit old, so I will try upgrading them and report back if this still happens with the latest version. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora |
From: Daniel P. B. <ber...@re...> - 2009-02-24 13:51:36
|
Quite some months ago now, sourceforge discontinued access to the general project shell server. This meant we could no longer publish our Mercurial repository. After an abortive attempt to move to FSF's savannah.org, we settled on the GNOME hosting service and have now got everything we need up and running. Our new project home page can be found at: http://live.gnome.org/gtk-vnc Instead of Mercurial we are using GIT which can be accessed anonymously using: git clone git://git.gnome.org/gtk-vnc Or browsable online at http://git.gnome.org/cgit/gtk-vnc/ The new developers & users mailing list is here: http://mail.gnome.org/mailman/listinfo/gtk-vnc-list The new download site for official releases is here: http://ftp.gnome.org/pub/GNOME/sources/gtk-vnc The existing released tar.gz on sourceforge.net download site will remain, but the sf.net mailing list will be disabled and all future discussions will be on the GNOME gtk-vnc-list We are *not* bulk re-subscribing people, so please make sure you register with the new mailing list if you wish to continue to follow development Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| |
From: Anthony L. <an...@co...> - 2009-02-23 21:24:18
|
Jonh Wendell wrote: > Hello, this is reported at > https://bugs.launchpad.net/ubuntu/+source/gtk-vnc/+bug/276966 > > Here is an attempt to fix this issue. I haven't tested it yet, since it > isn't easily reproducible. > > Comments? > Doesn't seem right to me. priv->image will always be valid as long as the object is valid. Are you passsing in NULL to the function? Do you have multiple threads racing each other? Regards, Anthony Liguori > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------------ > Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA > -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise > -Strategies to boost innovation and cut costs with open source participation > -Receive a $600 discount off the registration fee with the source code: SFAD > http://p.sf.net/sfu/XcvMzF8H > ------------------------------------------------------------------------ > > _______________________________________________ > Gtk-vnc-devel mailing list > Gtk...@li... > https://lists.sourceforge.net/lists/listinfo/gtk-vnc-devel |
From: Daniel P. B. <ber...@re...> - 2009-02-19 14:51:49
|
On Thu, Feb 19, 2009 at 11:34:52AM -0300, Jonh Wendell wrote: > Hi, folks, with this trivial patch I'm able to connect into ipv6 address > hosts. Also, I changed a bit the error messages in debug output. > > Okay? No, this is wrong. Please see this page for a description of why it is wrong http://people.redhat.com/drepper/userapi-ipv6.html "AI_ADDRCONFIG This flag should always be set when the returned values are needed to make connections. If no specific protocol is requested, the Linux getaddrinfo implementation returns both IPv4 and IPv6 addresses. This can be less than optimal and is certainly slower if the machine has only interfaces for one protocol. These days there are still many systems which have no configured IPv6 address at all. In that case using an IPv6 address will always fail. Worse, it might cause the IPv6 kernel module to be loaded unnecessarily. Using AI_ADDRCONFIG avoids this by determining what protocols are supported by the currently configured network interfaces and return only addresses for those." Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| |
From: Jonh W. <jwe...@gn...> - 2009-02-19 14:35:09
|
Hi, folks, with this trivial patch I'm able to connect into ipv6 address hosts. Also, I changed a bit the error messages in debug output. Okay? -- Jonh Wendell http://www.bani.com.br |
From: Jonh W. <jwe...@gn...> - 2009-02-13 14:26:22
|
Hello, this is reported at https://bugs.launchpad.net/ubuntu/+source/gtk-vnc/+bug/276966 Here is an attempt to fix this issue. I haven't tested it yet, since it isn't easily reproducible. Comments? -- Jonh Wendell http://www.bani.com.br |
From: Daniel P. B. <ber...@re...> - 2009-02-04 17:35:09
|
This patch is the counterpart to one I just sent to qemu-devel to add support for a new SASL authentication type. This was recently assigned an offiical auth code http://realvnc.com/pipermail/vnc-list/2008-December/059463.html And the protocol is described here: http://realvnc.com/pipermail/vnc-list/2008-December/059462.html This is pretty much just a straight impl of this protocol into GTK-VNC. It fully supports SASL SSF layers, so suitable SASL mechanisms (like GSSAPI) can provide encryption as well as authentication. Alternatively, it will layer SASL over the existing VeNCrypt extension which uses TLS. This is hooked up with our existing auth callback support, so it will work with any SASL mechanims requiring passwords, or usernames. We can add more callbacks if it is determined to be needed. GSSAPI doesn't need any callbacks, automatically locating your Kerberos principle. The impl uses Cyrus-SASL which is common on all Linux boxes. If not present, the SASL extension will be disabled. configure.ac | 47 ++ examples/gvncviewer.c | 4 src/Makefile.am | 4 src/gvnc.c | 919 ++++++++++++++++++++++++++++++++++++++++++-------- src/gvnc.h | 6 src/vncdisplay.c | 14 6 files changed, 852 insertions(+), 142 deletions(-) Daniel diff -r d68935d582f0 configure.ac --- a/configure.ac Sun Dec 07 19:56:56 2008 +0000 +++ b/configure.ac Wed Feb 04 17:26:10 2009 +0000 @@ -140,16 +140,63 @@ fi AC_DEFINE_UNQUOTED(WITH_LIBVIEW,[$WITH_LIBVIEW], [Whether to use libview]) AC_SUBST(VIEW_CFLAGS) AC_SUBST(VIEW_LIBS) PKG_CHECK_MODULES(GNUTLS, gnutls >= $GNUTLS_REQUIRED) AC_SUBST(GNUTLS_CFLAGS) AC_SUBST(GNUTLS_LIBS) +dnl Cyrus SASL +AC_ARG_WITH([sasl], + [ --with-sasl use cyrus SASL for authentication], + [], + [with_sasl=check]) + +SASL_CFLAGS= +SASL_LIBS= +if test "x$with_sasl" != "xno"; then + if test "x$with_sasl" != "xyes" -a "x$with_sasl" != "xcheck"; then + SASL_CFLAGS="-I$with_sasl" + SASL_LIBS="-L$with_sasl" + fi + fail=0 + old_cflags="$CFLAGS" + old_libs="$LIBS" + CFLAGS="$CFLAGS $SASL_CFLAGS" + LIBS="$LIBS $SASL_LIBS" + AC_CHECK_HEADER([sasl/sasl.h],[],[ + if test "x$with_sasl" != "xcheck" ; then + with_sasl=no + else + fail=1 + fi]) + if test "x$with_sasl" != "xno" ; then + AC_CHECK_LIB([sasl2], [sasl_client_init],[with_sasl=yes],[ + if test "x$with_sasl" = "xcheck" ; then + with_sasl=no + else + fail=1 + fi]) + fi + test $fail = 1 && + AC_MSG_ERROR([You must install the Cyrus SASL development package in order to compile GTK-VNC]) + CFLAGS="$old_cflags" + LIBS="$old_libs" + SASL_LIBS="$SASL_LIBS -lsasl2" + if test "x$with_sasl" = "xyes" ; then + AC_DEFINE_UNQUOTED([HAVE_SASL], 1, + [whether Cyrus SASL is available for authentication]) + fi +fi +AM_CONDITIONAL([HAVE_SASL], [test "x$with_sasl" = "xyes"]) +AC_SUBST([SASL_CFLAGS]) +AC_SUBST([SASL_LIBS]) + + GTHREAD_CFLAGS= GTHREAD_LIBS= AC_CHECK_LIB(z, inflate, [], [AC_MSG_ERROR([zlib not found])]) WITH_UCONTEXT=1 AC_ARG_WITH(coroutine, diff -r d68935d582f0 examples/gvncviewer.c --- a/examples/gvncviewer.c Sun Dec 07 19:56:56 2008 +0000 +++ b/examples/gvncviewer.c Wed Feb 04 17:26:10 2009 +0000 @@ -235,18 +235,22 @@ static void vnc_credential(GtkWidget *vn if (response == GTK_RESPONSE_OK) { for (i = 0, row = 0 ; i < credList->n_values ; i++) { GValue *cred = g_value_array_get_nth(credList, i); switch (g_value_get_enum(cred)) { case VNC_DISPLAY_CREDENTIAL_USERNAME: case VNC_DISPLAY_CREDENTIAL_PASSWORD: data[i] = gtk_entry_get_text(GTK_ENTRY(entry[row])); + fprintf(stderr, "**********o %s\n", data[i]); break; + default: + continue; } + row++; } } } for (i = 0 ; i < credList->n_values ; i++) { GValue *cred = g_value_array_get_nth(credList, i); if (data[i]) { if (vnc_display_set_credential(VNC_DISPLAY(vncdisplay), diff -r d68935d582f0 src/Makefile.am --- a/src/Makefile.am Sun Dec 07 19:56:56 2008 +0000 +++ b/src/Makefile.am Wed Feb 04 17:26:10 2009 +0000 @@ -1,18 +1,18 @@ EXTRA_DIST = libgtk-vnc_sym.version vncmarshal.txt lib_LTLIBRARIES = libgtk-vnc-1.0.la libgtk_vnc_1_0_la_LIBADD = @GTK_LIBS@ @GNUTLS_LIBS@ \ - @GTHREAD_LIBS@ \ + @GTHREAD_LIBS@ @SASL_LIBS@ \ ../gnulib/lib/libgnu.la libgtk_vnc_1_0_la_CFLAGS = @GTK_CFLAGS@ @GNUTLS_CFLAGS@ \ - @GTHREAD_CFLAGS@ @WARNING_CFLAGS@ \ + @GTHREAD_CFLAGS@ @SASL_CFLAGS@ @WARNING_CFLAGS@ \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DG_LOG_DOMAIN=\"gtk-vnc\" \ -I$(top_srcdir)/gnulib/lib -I../gnulib/lib libgtk_vnc_1_0_la_LDFLAGS = -Wl, @LD_VERSION_SCRIPT_SUPPORT@ \ -version-info 0:1:0 -no-undefined gtk_vnc_includedir = $(includedir)/gtk-vnc-1.0/ gtk_vnc_include_HEADERS = vncdisplay.h diff -r d68935d582f0 src/gvnc.c --- a/src/gvnc.c Sun Dec 07 19:56:56 2008 +0000 +++ b/src/gvnc.c Wed Feb 04 17:26:10 2009 +0000 @@ -41,16 +41,20 @@ #include "d3des.h" #include "x_keymap.h" #include "utils.h" #include <gnutls/gnutls.h> #include <gnutls/x509.h> +#ifdef HAVE_SASL +#include <sasl/sasl.h> +#endif + #include <zlib.h> #include <gdk/gdkkeysyms.h> #include "getaddrinfo.h" /* AI_ADDRCONFIG is missing on some systems and gnulib won't provide it even if its emulated getaddrinfo() for us . */ @@ -128,16 +132,26 @@ struct gvnc unsigned int auth_type; unsigned int auth_subtype; char *cred_username; char *cred_password; char *cred_x509_cacert; char *cred_x509_cacrl; char *cred_x509_cert; char *cred_x509_key; + gboolean want_cred_username; + gboolean want_cred_password; + gboolean want_cred_x509; + +#if HAVE_SASL + sasl_conn_t *saslconn; /* SASL context */ + const char *saslDecoded; + unsigned int saslDecodedLength; + unsigned int saslDecodedOffset; +#endif char read_buffer[4096]; size_t read_offset; size_t read_size; char write_buffer[4096]; size_t write_offset; @@ -350,16 +364,143 @@ static int gvnc_zread(struct gvnc *gvnc, } } return offset; } /* IO functions */ + +/* + * Read at least 1 more byte of data straight off the wire + * into the requested buffer. + */ +static int gvnc_read_wire(struct gvnc *gvnc, void *data, size_t len) +{ + int ret; + + reread: + if (gvnc->tls_session) { + ret = gnutls_read(gvnc->tls_session, data, len); + if (ret < 0) { + if (ret == GNUTLS_E_AGAIN) + errno = EAGAIN; + else + errno = EIO; + ret = -1; + } + } else + ret = recv (gvnc->fd, data, len, 0); + + if (ret == -1) { + switch (errno) { + case EWOULDBLOCK: + if (gvnc->wait_interruptable) { + if (!g_io_wait_interruptable(&gvnc->wait, + gvnc->channel, G_IO_IN)) { + GVNC_DEBUG("Read blocking interrupted %d", gvnc->has_error); + return -EAGAIN; + } + } else + g_io_wait(gvnc->channel, G_IO_IN); + case EINTR: + goto reread; + + default: + GVNC_DEBUG("Closing the connection: gvnc_read() - errno=%d\n", errno); + gvnc->has_error = TRUE; + return -errno; + } + } + if (ret == 0) { + GVNC_DEBUG("Closing the connection: gvnc_read() - ret=0\n"); + gvnc->has_error = TRUE; + return -EPIPE; + } + //GVNC_DEBUG("Read wire %p %d -> %d", data, len, ret); + + return ret; +} + + +/* + * Read at least 1 more byte of data out of the SASL decrypted + * data buffer, into the internal read buffer + */ +static int gvnc_read_sasl(struct gvnc *gvnc) +{ + size_t want; + //GVNC_DEBUG("Read SASL %p size %d offset %d", gvnc->saslDecoded, + // gvnc->saslDecodedLength, gvnc->saslDecodedOffset); + if (gvnc->saslDecoded == NULL) { + char encoded[8192]; + int encodedLen = sizeof(encoded); + int err, ret; + + ret = gvnc_read_wire(gvnc, encoded, encodedLen); + if (ret < 0) { + return ret; + } + + err = sasl_decode(gvnc->saslconn, encoded, ret, + &gvnc->saslDecoded, &gvnc->saslDecodedLength); + if (err != SASL_OK) { + GVNC_DEBUG("Failed to decode SASL data %s", + sasl_errstring(err, NULL, NULL)); + gvnc->has_error = TRUE; + return -EINVAL; + } + gvnc->saslDecodedOffset = 0; + } + + want = gvnc->saslDecodedLength - gvnc->saslDecodedOffset; + if (want > sizeof(gvnc->read_buffer)) + want = sizeof(gvnc->read_buffer); + + memcpy(gvnc->read_buffer, + gvnc->saslDecoded + gvnc->saslDecodedOffset, + want); + gvnc->saslDecodedOffset += want; + if (gvnc->saslDecodedOffset == gvnc->saslDecodedLength) { + gvnc->saslDecodedLength = gvnc->saslDecodedOffset = 0; + gvnc->saslDecoded = NULL; + } + //GVNC_DEBUG("Done read write %d - %d", want, gvnc->has_error); + return want; +} + + +/* + * Read at least 1 more byte of data straight off the wire + * into the internal read buffer + */ +static int gvnc_read_plain(struct gvnc *gvnc) +{ + //GVNC_DEBUG("Read plain %d", sizeof(gvnc->read_buffer)); + return gvnc_read_wire(gvnc, gvnc->read_buffer, sizeof(gvnc->read_buffer)); +} + +/* + * Read at least 1 more byte of data into the internal read_buffer + */ +static int gvnc_read_buf(struct gvnc *gvnc) +{ + //GVNC_DEBUG("Start read %d", gvnc->has_error); +#if HAVE_SASL + if (gvnc->saslconn) + return gvnc_read_sasl(gvnc); + else +#endif + return gvnc_read_plain(gvnc); +} + +/* + * Fill the 'data' buffer up with exactly 'len' bytes worth of data + */ static int gvnc_read(struct gvnc *gvnc, void *data, size_t len) { char *ptr = data; size_t offset = 0; if (gvnc->has_error) return -EINVAL; while (offset < len) { @@ -372,89 +513,63 @@ static int gvnc_read(struct gvnc *gvnc, if (ret == -1) { GVNC_DEBUG("Closing the connection: gvnc_read() - gvnc_zread() failed\n"); gvnc->has_error = TRUE; return -errno; } offset += ret; continue; } else if (gvnc->read_offset == gvnc->read_size) { - int ret; + int ret = gvnc_read_buf(gvnc); - if (gvnc->tls_session) { - ret = gnutls_read(gvnc->tls_session, gvnc->read_buffer, 4096); - if (ret < 0) { - if (ret == GNUTLS_E_AGAIN) - errno = EAGAIN; - else - errno = EIO; - ret = -1; - } - } else - ret = recv (gvnc->fd, gvnc->read_buffer, 4096, 0); - - if (ret == -1) { - switch (errno) { - case EWOULDBLOCK: - if (gvnc->wait_interruptable) { - if (!g_io_wait_interruptable(&gvnc->wait, - gvnc->channel, G_IO_IN)) - return -EAGAIN; - } else - g_io_wait(gvnc->channel, G_IO_IN); - case EINTR: - continue; - default: - GVNC_DEBUG("Closing the connection: gvnc_read() - errno=%d\n", errno); - gvnc->has_error = TRUE; - return -errno; - } - } - if (ret == 0) { - GVNC_DEBUG("Closing the connection: gvnc_read() - ret=0\n"); - gvnc->has_error = TRUE; - return -EPIPE; - } - + if (ret < 0) + return ret; gvnc->read_offset = 0; gvnc->read_size = ret; } tmp = MIN(gvnc->read_size - gvnc->read_offset, len - offset); memcpy(ptr + offset, gvnc->read_buffer + gvnc->read_offset, tmp); gvnc->read_offset += tmp; offset += tmp; } return 0; } -static void gvnc_flush(struct gvnc *gvnc) +/* + * Write all 'data' of length 'datalen' bytes out to + * the wire + */ +static void gvnc_flush_wire(struct gvnc *gvnc, + const void *data, + size_t datalen) { size_t offset = 0; - while (offset < gvnc->write_offset) { + //GVNC_DEBUG("Flush write %p %d", data, datalen); + while (offset < datalen) { int ret; if (gvnc->tls_session) { ret = gnutls_write(gvnc->tls_session, - gvnc->write_buffer+offset, - gvnc->write_offset-offset); + data+offset, + datalen-offset); if (ret < 0) { if (ret == GNUTLS_E_AGAIN) errno = EAGAIN; else errno = EIO; ret = -1; } } else ret = send (gvnc->fd, - gvnc->write_buffer+offset, - gvnc->write_offset-offset, 0); + data+offset, + datalen-offset, 0); if (ret == -1) { switch (errno) { case EWOULDBLOCK: g_io_wait(gvnc->channel, G_IO_OUT); case EINTR: continue; default: GVNC_DEBUG("Closing the connection: gvnc_flush %d\n", errno); @@ -464,16 +579,67 @@ static void gvnc_flush(struct gvnc *gvnc } if (ret == 0) { GVNC_DEBUG("Closing the connection: gvnc_flush\n"); gvnc->has_error = TRUE; return; } offset += ret; } +} + + +/* + * Encode all buffered data, write all encrypted data out + * to the wire + */ +static void gvnc_flush_sasl(struct gvnc *gvnc) +{ + const char *output; + unsigned int outputlen; + int err; + + err = sasl_encode(gvnc->saslconn, + gvnc->write_buffer, + gvnc->write_offset, + &output, &outputlen); + if (err != SASL_OK) { + GVNC_DEBUG("Failed to encode SASL data %s", + sasl_errstring(err, NULL, NULL)); + gvnc->has_error = TRUE; + return; + } + //GVNC_DEBUG("Flush SASL %d: %p %d", gvnc->write_offset, output, outputlen); + gvnc_flush_wire(gvnc, output, outputlen); +} + +/* + * Write all buffered data straight out to the wire + */ +static void gvnc_flush_plain(struct gvnc *gvnc) +{ + //GVNC_DEBUG("Flush plain %d", gvnc->write_offset); + gvnc_flush_wire(gvnc, + gvnc->write_buffer, + gvnc->write_offset); +} + + +/* + * Write all buffered data out to the wire + */ +static void gvnc_flush(struct gvnc *gvnc) +{ + //GVNC_DEBUG("STart write %d", gvnc->has_error); +#if HAVE_SASL + if (gvnc->saslconn) + gvnc_flush_sasl(gvnc); + else +#endif + gvnc_flush_plain(gvnc); gvnc->write_offset = 0; } static void gvnc_write(struct gvnc *gvnc, const void *data, size_t len) { const char *ptr = data; size_t offset = 0; @@ -2115,16 +2281,74 @@ gboolean gvnc_server_message(struct gvnc GVNC_DEBUG("Received an unknown message: %u\n", msg); gvnc->has_error = TRUE; break; } return !gvnc_has_error(gvnc); } +gboolean gvnc_wants_credential_password(struct gvnc *gvnc) +{ + return gvnc->want_cred_password; +} + +gboolean gvnc_wants_credential_username(struct gvnc *gvnc) +{ + return gvnc->want_cred_username; +} + +gboolean gvnc_wants_credential_x509(struct gvnc *gvnc) +{ + return gvnc->want_cred_x509; +} + +static gboolean gvnc_has_credentials(gpointer data) +{ + struct gvnc *gvnc = (struct gvnc *)data; + + if (gvnc->has_error) + return TRUE; + if (gvnc_wants_credential_username(gvnc) && !gvnc->cred_username) + return FALSE; + if (gvnc_wants_credential_password(gvnc) && !gvnc->cred_password) + return FALSE; + /* + * For x509 we require a minimum of the CA cert. + * Anything else is a bonus - though the server + * may reject auth if it decides it wants a client + * cert. We can't express that based on auth type + * alone though - we'll merely find out when TLS + * negotiation takes place. + */ + if (gvnc_wants_credential_x509(gvnc) && !gvnc->cred_x509_cacert) + return FALSE; + return TRUE; +} + +static gboolean gvnc_gather_credentials(struct gvnc *gvnc) +{ + if (!gvnc_has_credentials(gvnc)) { + GVNC_DEBUG("Requesting missing credentials\n"); + if (gvnc->has_error || !gvnc->ops.auth_cred) { + gvnc->has_error = TRUE; + return FALSE; + } + if (!gvnc->ops.auth_cred(gvnc->ops_data)) + gvnc->has_error = TRUE; + if (gvnc->has_error) + return FALSE; + GVNC_DEBUG("Waiting for missing credentials\n"); + g_condition_wait(gvnc_has_credentials, gvnc); + GVNC_DEBUG("Got all credentials\n"); + } + return !gvnc_has_error(gvnc); +} + + static gboolean gvnc_check_auth_result(struct gvnc *gvnc) { uint32_t result; GVNC_DEBUG("Checking auth result\n"); result = gvnc_read_u32(gvnc); if (!result) { GVNC_DEBUG("Success\n"); return TRUE; @@ -2137,29 +2361,35 @@ static gboolean gvnc_check_auth_result(s if (len > (sizeof(reason)-1)) return FALSE; gvnc_read(gvnc, reason, len); reason[len] = '\0'; GVNC_DEBUG("Fail %s\n", reason); if (!gvnc->has_error && gvnc->ops.auth_failure) gvnc->ops.auth_failure(gvnc->ops_data, reason); } else { - GVNC_DEBUG("Fail\n"); + GVNC_DEBUG("Fail auth no result\n"); if (!gvnc->has_error && gvnc->ops.auth_failure) gvnc->ops.auth_failure(gvnc->ops_data, NULL); } return FALSE; } static gboolean gvnc_perform_auth_vnc(struct gvnc *gvnc) { uint8_t challenge[16]; uint8_t key[8]; GVNC_DEBUG("Do Challenge\n"); + gvnc->want_cred_password = TRUE; + gvnc->want_cred_username = FALSE; + gvnc->want_cred_x509 = FALSE; + if (!gvnc_gather_credentials(gvnc)) + return FALSE; + if (!gvnc->cred_password) return FALSE; gvnc_read(gvnc, challenge, 16); memset(key, 0, 8); strncpy((char*)key, (char*)gvnc->cred_password, 8); @@ -2168,16 +2398,482 @@ static gboolean gvnc_perform_auth_vnc(st des(challenge + 8, challenge + 8); gvnc_write(gvnc, challenge, 16); gvnc_flush(gvnc); return gvnc_check_auth_result(gvnc); } +#if HAVE_SASL +/* + * NB, keep in sync with similar method in qemud/remote.c + */ +static char *gvnc_addr_to_string(struct sockaddr_storage *sa, socklen_t salen) +{ + char host[NI_MAXHOST], port[NI_MAXSERV]; + char *addr; + int err; + + if ((err = getnameinfo((struct sockaddr *)sa, salen, + host, sizeof(host), + port, sizeof(port), + NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { + GVNC_DEBUG("Cannot resolve address %d: %s", + err, gai_strerror(err)); + return NULL; + } + + addr = g_malloc0(strlen(host) + 1 + strlen(port) + 1); + strcpy(addr, host); + strcat(addr, ";"); + strcat(addr, port); + return addr; +} + + + +static gboolean +gvnc_gather_sasl_credentials(struct gvnc *gvnc, + sasl_interact_t *interact) +{ + int ninteract; + + gvnc->want_cred_password = FALSE; + gvnc->want_cred_username = FALSE; + gvnc->want_cred_x509 = FALSE; + + for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) { + switch (interact[ninteract].id) { + case SASL_CB_AUTHNAME: + case SASL_CB_USER: + gvnc->want_cred_username = TRUE; + break; + + case SASL_CB_PASS: + gvnc->want_cred_password = TRUE; + break; + + default: + GVNC_DEBUG("Unsupported credential %lu", + interact[ninteract].id); + /* Unsupported */ + return FALSE; + } + } + + if ((gvnc->want_cred_password || + gvnc->want_cred_username) && + !gvnc_gather_credentials(gvnc)) { + GVNC_DEBUG("%s", "damn "); + return FALSE; + } + + for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) { + switch (interact[ninteract].id) { + case SASL_CB_AUTHNAME: + case SASL_CB_USER: + interact[ninteract].result = gvnc->cred_username; + interact[ninteract].len = strlen(gvnc->cred_username); + GVNC_DEBUG("Gather Username %s", gvnc->cred_username); + break; + + case SASL_CB_PASS: + interact[ninteract].result = gvnc->cred_password; + interact[ninteract].len = strlen(gvnc->cred_password); + GVNC_DEBUG("Gather Password %s", gvnc->cred_password); + break; + } + } + + GVNC_DEBUG("%s", "Filled SASL interact"); + + return TRUE; +} + + + +/* + * + * Init msg from server + * + * u32 mechlist-length + * u8-array mechlist-string + * + * Start msg to server + * + * u32 mechname-length + * u8-array mechname-string + * u32 clientout-length + * u8-array clientout-string + * + * Start msg from server + * + * u32 serverin-length + * u8-array serverin-string + * u8 continue + * + * Step msg to server + * + * u32 clientout-length + * u8-array clientout-string + * + * Step msg from server + * + * u32 serverin-length + * u8-array serverin-string + * u8 continue + */ + +#define SASL_MAX_MECHLIST_LEN 300 +#define SASL_MAX_MECHNAME_LEN 100 +#define SASL_MAX_DATA_LEN (1024 * 1024) + +/* Perform the SASL authentication process + */ +static gboolean gvnc_perform_auth_sasl(struct gvnc *gvnc) +{ + sasl_conn_t *saslconn = NULL; + sasl_security_properties_t secprops; + const char *clientout; + char *serverin = NULL; + unsigned int clientoutlen, serverinlen; + int err, complete; + struct sockaddr_storage sa; + socklen_t salen; + char *localAddr = NULL, *remoteAddr = NULL; + const void *val; + sasl_ssf_t ssf; + sasl_callback_t saslcb[] = { + { .id = SASL_CB_AUTHNAME }, + // { .id = SASL_CB_USER }, + { .id = SASL_CB_PASS }, + { .id = 0 }, + }; + sasl_interact_t *interact = NULL; + guint32 mechlistlen; + char *mechlist; + const char *mechname; + gboolean ret; + + /* Sets up the SASL library as a whole */ + err = sasl_client_init(NULL); + GVNC_DEBUG("Client initialize SASL authentication %d", err); + if (err != SASL_OK) { + GVNC_DEBUG("failed to initialize SASL library: %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + goto error; + } + + /* Get local address in form IPADDR:PORT */ + salen = sizeof(sa); + if (getsockname(gvnc->fd, (struct sockaddr*)&sa, &salen) < 0) { + GVNC_DEBUG("failed to get sock address %d (%s)", + errno, strerror(errno)); + goto error; + } + if ((localAddr = gvnc_addr_to_string(&sa, salen)) == NULL) + goto error; + + /* Get remote address in form IPADDR:PORT */ + salen = sizeof(sa); + if (getpeername(gvnc->fd, (struct sockaddr*)&sa, &salen) < 0) { + GVNC_DEBUG("failed to get peer address %d (%s)", + errno, strerror(errno)); + g_free(localAddr); + goto error; + } + if ((remoteAddr = gvnc_addr_to_string(&sa, salen)) == NULL) { + g_free(localAddr); + goto error; + } + + GVNC_DEBUG("Client SASL new host:'%s' local:'%s' remote:'%s'", gvnc->host, localAddr, remoteAddr); + + /* Setup a handle for being a client */ + err = sasl_client_new("vnc", + gvnc->host, + localAddr, + remoteAddr, + saslcb, + SASL_SUCCESS_DATA, + &saslconn); + g_free(localAddr); + g_free(remoteAddr); + + if (err != SASL_OK) { + GVNC_DEBUG("Failed to create SASL client context: %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + goto error; + } + + /* Initialize some connection props we care about */ + if (gvnc->tls_session) { + gnutls_cipher_algorithm_t cipher; + + cipher = gnutls_cipher_get(gvnc->tls_session); + if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) { + GVNC_DEBUG("%s", "invalid cipher size for TLS session"); + goto error; + } + ssf *= 8; /* key size is bytes, sasl wants bits */ + + GVNC_DEBUG("Setting external SSF %d", ssf); + err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf); + if (err != SASL_OK) { + GVNC_DEBUG("cannot set external SSF %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + goto error; + } + } + + memset (&secprops, 0, sizeof secprops); + /* If we've got TLS, we don't care about SSF */ + secprops.min_ssf = gvnc->tls_session ? 0 : 56; /* Equiv to DES supported by all Kerberos */ + secprops.max_ssf = gvnc->tls_session ? 0 : 100000; /* Very strong ! AES == 256 */ + secprops.maxbufsize = 100000; + /* If we're not TLS, then forbid any anonymous or trivially crackable auth */ + secprops.security_flags = gvnc->tls_session ? 0 : + SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; + + err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops); + if (err != SASL_OK) { + GVNC_DEBUG("cannot set security props %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + goto error; + } + + /* Get the supported mechanisms from the server */ + mechlistlen = gvnc_read_u32(gvnc); + if (gvnc->has_error) + goto error; + if (mechlistlen > SASL_MAX_MECHLIST_LEN) { + GVNC_DEBUG("mechlistlen %d too long", mechlistlen); + goto error; + } + + mechlist = g_malloc(mechlistlen+1); + gvnc_read(gvnc, mechlist, mechlistlen); + mechlist[mechlistlen] = '\0'; + if (gvnc->has_error) { + g_free(mechlist); + mechlist = NULL; + goto error; + } + +#if 0 + if (wantmech) { + if (strstr(mechlist, wantmech) == NULL) { + GVNC_DEBUG("SASL mechanism %s not supported by server", + wantmech); + VIR_FREE(iret.mechlist); + goto error; + } + mechlist = wantmech; + } +#endif + + restart: + /* Start the auth negotiation on the client end first */ + GVNC_DEBUG("Client start negotiation mechlist '%s'", mechlist); + err = sasl_client_start(saslconn, + mechlist, + &interact, + &clientout, + &clientoutlen, + &mechname); + if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) { + GVNC_DEBUG("Failed to start SASL negotiation: %d (%s)", + err, sasl_errdetail(saslconn)); + g_free(mechlist); + mechlist = NULL; + goto error; + } + + /* Need to gather some credentials from the client */ + if (err == SASL_INTERACT) { + if (!gvnc_gather_sasl_credentials(gvnc, + interact)) { + GVNC_DEBUG("%s", "Failed to collect auth credentials"); + goto error; + } + goto restart; + } + + GVNC_DEBUG("Server start negotiation with mech %s. Data %d bytes %p '%s'", + mechname, clientoutlen, clientout, clientout); + + if (clientoutlen > SASL_MAX_DATA_LEN) { + GVNC_DEBUG("SASL negotiation data too long: %d bytes", + clientoutlen); + goto error; + } + + /* Send back the chosen mechname */ + gvnc_write_u32(gvnc, strlen(mechname)); + gvnc_write(gvnc, mechname, strlen(mechname)); + + /* NB, distinction of NULL vs "" is *critical* in SASL */ + if (clientout) { + gvnc_write_u32(gvnc, clientoutlen + 1); + gvnc_write(gvnc, clientout, clientoutlen + 1); + } else { + gvnc_write_u32(gvnc, 0); + } + gvnc_flush(gvnc); + if (gvnc->has_error) + goto error; + + + GVNC_DEBUG("%s", "Getting sever start negotiation reply"); + /* Read the 'START' message reply from server */ + serverinlen = gvnc_read_u32(gvnc); + if (gvnc->has_error) + goto error; + if (serverinlen > SASL_MAX_DATA_LEN) { + GVNC_DEBUG("SASL negotiation data too long: %d bytes", + clientoutlen); + goto error; + } + + /* NB, distinction of NULL vs "" is *critical* in SASL */ + if (serverinlen) { + serverin = g_malloc(serverinlen); + gvnc_read(gvnc, serverin, serverinlen); + serverin[serverinlen-1] = '\0'; + serverinlen--; + } else { + serverin = NULL; + } + complete = gvnc_read_u8(gvnc); + if (gvnc->has_error) + goto error; + + GVNC_DEBUG("Client start result complete: %d. Data %d bytes %p '%s'", + complete, serverinlen, serverin, serverin); + + /* Loop-the-loop... + * Even if the server has completed, the client must *always* do at least one step + * in this loop to verify the server isn't lying about something. Mutual auth */ + for (;;) { + restep: + err = sasl_client_step(saslconn, + serverin, + serverinlen, + &interact, + &clientout, + &clientoutlen); + if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) { + GVNC_DEBUG("Failed SASL step: %d (%s)", + err, sasl_errdetail(saslconn)); + goto error; + } + + /* Need to gather some credentials from the client */ + if (err == SASL_INTERACT) { + if (!gvnc_gather_sasl_credentials(gvnc, + interact)) { + GVNC_DEBUG("%s", "Failed to collect auth credentials"); + goto error; + } + goto restep; + } + + if (serverin) { + g_free(serverin); + serverin = NULL; + } + + GVNC_DEBUG("Client step result %d. Data %d bytes %p '%s'", err, clientoutlen, clientout, clientout); + + /* Previous server call showed completion & we're now locally complete too */ + if (complete && err == SASL_OK) + break; + + /* Not done, prepare to talk with the server for another iteration */ + + /* NB, distinction of NULL vs "" is *critical* in SASL */ + if (clientout) { + gvnc_write_u32(gvnc, clientoutlen + 1); + gvnc_write(gvnc, clientout, clientoutlen + 1); + } else { + gvnc_write_u32(gvnc, 0); + } + gvnc_flush(gvnc); + if (gvnc->has_error) + goto error; + + GVNC_DEBUG("Server step with %d bytes %p", clientoutlen, clientout); + + serverinlen = gvnc_read_u32(gvnc); + if (gvnc->has_error) + goto error; + if (serverinlen > SASL_MAX_DATA_LEN) { + GVNC_DEBUG("SASL negotiation data too long: %d bytes", + clientoutlen); + goto error; + } + + /* NB, distinction of NULL vs "" is *critical* in SASL */ + if (serverinlen) { + serverin = g_malloc(serverinlen); + gvnc_read(gvnc, serverin, serverinlen); + serverin[serverinlen-1] = '\0'; + serverinlen--; + } else { + serverin = NULL; + } + complete = gvnc_read_u8(gvnc); + if (gvnc->has_error) + goto error; + + GVNC_DEBUG("Client step result complete: %d. Data %d bytes %p '%s'", + complete, serverinlen, serverin, serverin); + + /* This server call shows complete, and earlier client step was OK */ + if (complete && err == SASL_OK) { + g_free(serverin); + serverin = NULL; + break; + } + } + + /* Check for suitable SSF if non-TLS */ + if (!gvnc->tls_session) { + err = sasl_getprop(saslconn, SASL_SSF, &val); + if (err != SASL_OK) { + GVNC_DEBUG("cannot query SASL ssf on connection %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + goto error; + } + ssf = *(const int *)val; + GVNC_DEBUG("SASL SSF value %d", ssf); + if (ssf < 56) { /* 56 == DES level, good for Kerberos */ + GVNC_DEBUG("negotiation SSF %d was not strong enough", ssf); + goto error; + } + } + + GVNC_DEBUG("%s", "SASL authentication complete"); + ret = gvnc_check_auth_result(gvnc); + /* This must come *after* check-auth-result, because the former + * is defined to be sent unencrypted, and setting saslconn turns + * on the SSF layer encryption processing */ + gvnc->saslconn = saslconn; + return ret; + + error: + gvnc->has_error = TRUE; + if (saslconn) + sasl_dispose(&saslconn); + return FALSE; +} +#endif /* HAVE_SASL */ + + static gboolean gvnc_start_tls(struct gvnc *gvnc, int anonTLS) { static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; static const int kx_priority[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0}; static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0}; int ret; @@ -2225,16 +2921,22 @@ static gboolean gvnc_start_tls(struct gv return FALSE; } if (gnutls_credentials_set(gvnc->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { gnutls_deinit(gvnc->tls_session); gvnc->has_error = TRUE; return FALSE; } } else { + gvnc->want_cred_password = FALSE; + gvnc->want_cred_username = FALSE; + gvnc->want_cred_x509 = TRUE; + if (!gvnc_gather_credentials(gvnc)) + return FALSE; + gnutls_certificate_credentials_t x509_cred = gvnc_tls_initialize_cert_cred(gvnc); if (!x509_cred) { gnutls_deinit(gvnc->tls_session); gvnc->has_error = TRUE; return FALSE; } if (gnutls_credentials_set(gvnc->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) { gnutls_deinit(gvnc->tls_session); @@ -2274,102 +2976,16 @@ static gboolean gvnc_start_tls(struct gv GVNC_DEBUG("Certificate validation failed\n"); gvnc->has_error = TRUE; return FALSE; } return TRUE; } } -gboolean gvnc_wants_credential_password(struct gvnc *gvnc) -{ - if (gvnc->auth_type == GVNC_AUTH_VNC) - return TRUE; - - if (gvnc->auth_type == GVNC_AUTH_TLS && - gvnc->auth_subtype == GVNC_AUTH_VNC) - return TRUE; - - if (gvnc->auth_type == GVNC_AUTH_VENCRYPT) { - if (gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_PLAIN || - gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_TLSVNC || - gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_TLSPLAIN || - gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509VNC || - gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509PLAIN) - return TRUE; - } - - return FALSE; -} - -gboolean gvnc_wants_credential_username(struct gvnc *gvnc) -{ - if (gvnc->auth_type == GVNC_AUTH_VENCRYPT) { - if (gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_PLAIN || - gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_TLSPLAIN || - gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509PLAIN) - return TRUE; - } - - return FALSE; -} - -gboolean gvnc_wants_credential_x509(struct gvnc *gvnc) -{ - if (gvnc->auth_type == GVNC_AUTH_VENCRYPT) { - if (gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509NONE || - gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509PLAIN || - gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509VNC) - return TRUE; - } - - return FALSE; -} - -static gboolean gvnc_has_credentials(gpointer data) -{ - struct gvnc *gvnc = (struct gvnc *)data; - - if (gvnc->has_error) - return TRUE; - if (gvnc_wants_credential_username(gvnc) && !gvnc->cred_username) - return FALSE; - if (gvnc_wants_credential_password(gvnc) && !gvnc->cred_password) - return FALSE; - /* - * For x509 we require a minimum of the CA cert. - * Anything else is a bonus - though the server - * may reject auth if it decides it wants a client - * cert. We can't express that based on auth type - * alone though - we'll merely find out when TLS - * negotiation takes place. - */ - if (gvnc_wants_credential_x509(gvnc) && !gvnc->cred_x509_cacert) - return FALSE; - return TRUE; -} - -static gboolean gvnc_gather_credentials(struct gvnc *gvnc) -{ - if (!gvnc_has_credentials(gvnc)) { - GVNC_DEBUG("Requesting missing credentials\n"); - if (gvnc->has_error || !gvnc->ops.auth_cred) { - gvnc->has_error = TRUE; - return TRUE; - } - if (!gvnc->ops.auth_cred(gvnc->ops_data)) - gvnc->has_error = TRUE; - if (gvnc->has_error) - return TRUE; - GVNC_DEBUG("Waiting for missing credentials\n"); - g_condition_wait(gvnc_has_credentials, gvnc); - GVNC_DEBUG("Got all credentials\n"); - } - return !gvnc_has_error(gvnc); -} static gboolean gvnc_has_auth_subtype(gpointer data) { struct gvnc *gvnc = (struct gvnc *)data; if (gvnc->has_error) return TRUE; if (gvnc->auth_subtype == GVNC_AUTH_INVALID) @@ -2388,18 +3004,20 @@ static gboolean gvnc_perform_auth_tls(st return FALSE; } GVNC_DEBUG("Completed TLS setup\n"); nauth = gvnc_read_u8(gvnc); if (gvnc_has_error(gvnc)) return FALSE; - if (nauth == 0) + if (nauth == 0) { + GVNC_DEBUG("No sub-auth types requested\n"); return gvnc_check_auth_result(gvnc); + } if (nauth > sizeof(auth)) { GVNC_DEBUG("Too many (%d) auth types\n", nauth); gvnc->has_error = TRUE; return FALSE; } for (i = 0 ; i < nauth ; i++) { auth[i] = gvnc_read_u8(gvnc); @@ -2419,29 +3037,30 @@ static gboolean gvnc_perform_auth_tls(st GVNC_DEBUG("Waiting for auth subtype\n"); g_condition_wait(gvnc_has_auth_subtype, gvnc); if (gvnc->has_error) return FALSE; GVNC_DEBUG("Choose auth %d\n", gvnc->auth_subtype); - if (!gvnc_gather_credentials(gvnc)) - return FALSE; - gvnc_write_u8(gvnc, gvnc->auth_subtype); gvnc_flush(gvnc); switch (gvnc->auth_subtype) { case GVNC_AUTH_NONE: if (gvnc->minor == 8) return gvnc_check_auth_result(gvnc); return TRUE; case GVNC_AUTH_VNC: return gvnc_perform_auth_vnc(gvnc); +#ifdef HAVE_SASL + case GVNC_AUTH_SASL: + return gvnc_perform_auth_sasl(gvnc); +#endif default: return FALSE; } return TRUE; } static gboolean gvnc_perform_auth_vencrypt(struct gvnc *gvnc) @@ -2514,16 +3133,17 @@ static gboolean gvnc_perform_auth_vencry GVNC_DEBUG("Server refused VeNCrypt auth %d %d\n", gvnc->auth_subtype, status); return FALSE; } switch (gvnc->auth_subtype) { case GVNC_AUTH_VENCRYPT_TLSNONE: case GVNC_AUTH_VENCRYPT_TLSPLAIN: case GVNC_AUTH_VENCRYPT_TLSVNC: + case GVNC_AUTH_VENCRYPT_TLSSASL: anonTLS = 1; break; default: anonTLS = 0; } if (!gvnc_start_tls(gvnc, anonTLS)) { GVNC_DEBUG("Could not start TLS\n"); @@ -2539,16 +3159,24 @@ static gboolean gvnc_perform_auth_vencry return gvnc_check_auth_result(gvnc); /* Regular VNC layered over TLS */ case GVNC_AUTH_VENCRYPT_TLSVNC: case GVNC_AUTH_VENCRYPT_X509VNC: GVNC_DEBUG("Handing off to VNC auth\n"); return gvnc_perform_auth_vnc(gvnc); +#ifdef HAVE_SASL + /* SASL layered over TLS */ + case GVNC_AUTH_VENCRYPT_TLSSASL: + case GVNC_AUTH_VENCRYPT_X509SASL: + GVNC_DEBUG("Handing off to SASL auth\n"); + return gvnc_perform_auth_sasl(gvnc); +#endif + default: return FALSE; } } static gboolean gvnc_has_auth_type(gpointer data) { struct gvnc *gvnc = (struct gvnc *)data; @@ -2621,16 +3249,21 @@ static gboolean gvnc_perform_auth(struct case GVNC_AUTH_TLS: if (gvnc->minor < 7) return FALSE; return gvnc_perform_auth_tls(gvnc); case GVNC_AUTH_VENCRYPT: return gvnc_perform_auth_vencrypt(gvnc); +#ifdef HAVE_SASL + case GVNC_AUTH_SASL: + return gvnc_perform_auth_sasl(gvnc); +#endif + default: if (gvnc->ops.auth_unsupported) gvnc->ops.auth_unsupported (gvnc->ops_data, gvnc->auth_type); gvnc->has_error = TRUE; return FALSE; } @@ -2666,16 +3299,21 @@ void gvnc_free(struct gvnc *gvnc) void gvnc_close(struct gvnc *gvnc) { int i; if (gvnc->tls_session) { gnutls_bye(gvnc->tls_session, GNUTLS_SHUT_RDWR); gvnc->tls_session = NULL; } +#if HAVE_SASL + if (gvnc->saslconn) + sasl_dispose (&gvnc->saslconn); +#endif + if (gvnc->channel) { g_io_channel_unref(gvnc->channel); gvnc->channel = NULL; } if (gvnc->fd != -1) { close(gvnc->fd); gvnc->fd = -1; } @@ -2982,31 +3620,34 @@ gboolean gvnc_open_host(struct gvnc *gvn } freeaddrinfo (ai); return FALSE; } gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type) { - GVNC_DEBUG("Requested auth type %u\n", type); + GVNC_DEBUG("Thinking about auth type %u", type); if (gvnc->auth_type != GVNC_AUTH_INVALID) { gvnc->has_error = TRUE; return !gvnc_has_error(gvnc); } if (type != GVNC_AUTH_NONE && type != GVNC_AUTH_VNC && type != GVNC_AUTH_TLS && - type != GVNC_AUTH_VENCRYPT) { + type != GVNC_AUTH_VENCRYPT && + type != GVNC_AUTH_SASL) { + GVNC_DEBUG("Unsupported auth type %u", type); if (gvnc->ops.auth_unsupported) - gvnc->ops.auth_unsupported (gvnc->ops_data, type); + gvnc->ops.auth_unsupported (gvnc->ops_data, type); gvnc->has_error = TRUE; return !gvnc_has_error(gvnc); } + GVNC_DEBUG("Decided on auth type %u", type); gvnc->auth_type = type; gvnc->auth_subtype = GVNC_AUTH_INVALID; return !gvnc_has_error(gvnc); } gboolean gvnc_set_auth_subtype(struct gvnc *gvnc, unsigned int type) { @@ -3022,41 +3663,41 @@ gboolean gvnc_set_auth_subtype(struct gv } gvnc->auth_subtype = type; return !gvnc_has_error(gvnc); } gboolean gvnc_set_credential_password(struct gvnc *gvnc, const char *password) { - GVNC_DEBUG("Set password credential\n"); + GVNC_DEBUG("Set password credential %s", password); if (gvnc->cred_password) g_free(gvnc->cred_password); if (!(gvnc->cred_password = g_strdup(password))) { gvnc->has_error = TRUE; return FALSE; } return TRUE; } gboolean gvnc_set_credential_username(struct gvnc *gvnc, const char *username) { - GVNC_DEBUG("Set username credential %s\n", username); + GVNC_DEBUG("Set username credential %s", username); if (gvnc->cred_username) g_free(gvnc->cred_username); if (!(gvnc->cred_username = g_strdup(username))) { gvnc->has_error = TRUE; return FALSE; } return TRUE; } gboolean gvnc_set_credential_x509_cacert(struct gvnc *gvnc, const char *file) { - GVNC_DEBUG("Set x509 cacert %s\n", file); + GVNC_DEBUG("Set x509 cacert %s", file); if (gvnc->cred_x509_cacert) g_free(gvnc->cred_x509_cacert); if (!(gvnc->cred_x509_cacert = g_strdup(file))) { gvnc->has_error = TRUE; return FALSE; } return TRUE; } diff -r d68935d582f0 src/gvnc.h --- a/src/gvnc.h Sun Dec 07 19:56:56 2008 +0000 +++ b/src/gvnc.h Wed Feb 04 17:26:10 2009 +0000 @@ -123,27 +123,31 @@ typedef enum { GVNC_AUTH_INVALID = 0, GVNC_AUTH_NONE = 1, GVNC_AUTH_VNC = 2, GVNC_AUTH_RA2 = 5, GVNC_AUTH_RA2NE = 6, GVNC_AUTH_TIGHT = 16, GVNC_AUTH_ULTRA = 17, GVNC_AUTH_TLS = 18, /* Used by VINO */ - GVNC_AUTH_VENCRYPT = 19 /* Used by VeNCrypt and QEMU */ + GVNC_AUTH_VENCRYPT = 19, /* Used by VeNCrypt and QEMU */ + GVNC_AUTH_SASL = 20, /* SASL type used by VINO and QEMU */ } gvnc_auth; typedef enum { GVNC_AUTH_VENCRYPT_PLAIN = 256, GVNC_AUTH_VENCRYPT_TLSNONE = 257, GVNC_AUTH_VENCRYPT_TLSVNC = 258, GVNC_AUTH_VENCRYPT_TLSPLAIN = 259, GVNC_AUTH_VENCRYPT_X509NONE = 260, GVNC_AUTH_VENCRYPT_X509VNC = 261, GVNC_AUTH_VENCRYPT_X509PLAIN = 262, + + GVNC_AUTH_VENCRYPT_TLSSASL = 300, /* XXX get official number */ + GVNC_AUTH_VENCRYPT_X509SASL = 301, /* XXX get official number */ } gvnc_auth_vencrypt; struct gvnc *gvnc_new(const struct gvnc_ops *ops, gpointer ops_data); void gvnc_free(struct gvnc *gvnc); void gvnc_close(struct gvnc *gvnc); void gvnc_shutdown(struct gvnc *gvnc); diff -r d68935d582f0 src/vncdisplay.c --- a/src/vncdisplay.c Sun Dec 07 19:56:56 2008 +0000 +++ b/src/vncdisplay.c Wed Feb 04 17:26:10 2009 +0000 @@ -1854,19 +1854,33 @@ static void vnc_display_init(VncDisplay priv->allow_lossy = FALSE; priv->allow_scaling = FALSE; priv->grab_pointer = FALSE; priv->grab_keyboard = FALSE; priv->local_pointer = FALSE; priv->shared_flag = FALSE; priv->force_size = TRUE; + /* + * Both these two provide TLS based auth, and can layer + * all the other auth types on top. So these two must + * be the first listed + */ priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_VENCRYPT)); priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_TLS)); + + /* + * Then stackable auth types in order of preference + */ + priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_SASL)); priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_VNC)); + + /* + * Or nothing at all + */ priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_NONE)); priv->gvnc = gvnc_new(&vnc_display_ops, obj); } static int vnc_display_best_path(char *buf, int buflen, const char *basedir, -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| |
From: Daniel P. B. <ber...@re...> - 2009-01-30 13:21:08
|
On Fri, Jan 30, 2009 at 09:16:41AM -0300, Jonh Wendell wrote: > Hello, folks. > > I wonder if it's possible o keep old versions of gtk-vnc available to > download at sourceforge. Currently the only version available is 0.3.8. Urm, they are all available for download - its just the crazy sf.net UI doesn't show them on the first download page - you have to navigate to the detailed download page: http://sourceforge.net/project/showfiles.php?group_id=190580&package_id=223580 Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| |
From: Jonh W. <jwe...@gn...> - 2009-01-30 12:37:30
|
Hello, folks. I wonder if it's possible o keep old versions of gtk-vnc available to download at sourceforge. Currently the only version available is 0.3.8. Some people might want to download older versions to run older vinagre, for example. http://bugzilla.gnome.org/show_bug.cgi?id=569215 Thanks, -- Jonh Wendell http://www.bani.com.br |
From: Jonh W. <jwe...@gn...> - 2009-01-08 12:54:03
|
Hello, folks. There's a bug reported in GNOME bugzilla about a numlock key issue: http://bugzilla.gnome.org/show_bug.cgi?id=562537 Could someone please take a look there? Thanks, -- Jonh Wendell http://www.bani.com.br |
From: Federico M. Q. <fed...@no...> - 2008-12-20 08:36:56
|
On Fri, 2008-12-19 at 22:50 -0600, Federico Mena Quintero wrote: > Hmm, so, the attached patch doesn't make me 100% happy, but using a > macro from Cairo is the only way I could find of detecting at > compile-time if GTK+ is built for X :( Ignore me, I'm on crack. This patch is broken - I'll send a good one on Monday. Federico |
From: Peter R. <pe...@ly...> - 2008-12-20 06:28:27
|
Den 2008-12-19 23:09 skrev Anthony Liguori: > Federico Mena Quintero wrote: >> On Wed, 2008-12-17 at 19:49 -0600, Anthony Liguori wrote: >> >>> This is a non-standard encoding and I don't see why it would be >>> helpful. How does it change things from a server's perspective? >>> >> Tight encoding is also non-standard ;) >> >> I was just matching what TightVNC does. >> > > But it's at least reserved. So is last rect, -224. According to spec, tight has 7, -1 - -222, -224 - -238 and -240 - -256. I believe it once had the entire -1 - -256 range but that some encodings where moved into the official spec. If you mean that the tight project may change the meaning of the -224 encoding, I guess you are right. But in that case they may also change encoding 7. But I for one don't think they are going to break backwards compatibility. At least not on purpose. Cheers, Peter |
From: Federico M. Q. <fed...@no...> - 2008-12-20 04:51:40
|
On Thu, 2008-12-18 at 20:20 +0000, Daniel P. Berrange wrote: > I have already applide this patch & it was in 0.3.8 release > > What tree did you generate your patches against ? Oops, something right after 0.3.7, it seems :) I didn't update my base tree until recently. [I should get off my ass and learn enough Mercurial to give you an Hg repository instead of Git patches, shouldn't I? ] Federico |
From: Federico M. Q. <fed...@no...> - 2008-12-20 04:50:24
|
On Thu, 2008-12-18 at 20:17 +0000, Daniel P. Berrange wrote: > ACk to the patch in principle, once its has been #ifdef'd to not hardcode > the use of GTK X backend on all platforms. Hmm, so, the attached patch doesn't make me 100% happy, but using a macro from Cairo is the only way I could find of detecting at compile-time if GTK+ is built for X :( Federico |
From: Federico M. Q. <fed...@no...> - 2008-12-20 04:40:06
|
On Thu, 2008-12-18 at 20:10 +0000, Daniel P. Berrange wrote: > ACK to Federico's patch then, provided we add this explanation in a > comment at the 'break' statement so we remember just why it works :-) Attached :) Federico |
From: Federico M. Q. <fed...@no...> - 2008-12-20 04:29:36
|
On Thu, 2008-12-18 at 20:20 +0100, Peter Rosin wrote: > I believe the idea is that the server can start sending the > update before it knows exactly how many rects it will need for > the update. It can thus state that the update will contain at > least some number of rects (probably 65535) and then end the > update at will later. So, there is no need to consume the > trailing rects, the server is not supposed to add any rects > after the "last rect". I imagine that in this specific case > e.g. a ptr movement rect can be inserted in the middle of a > number of tight rects, even if the ptr movement happened after > the update "started". Yes, exactly. This is GVNC_ENCODING_CURSOR_POS, which is currently not handled. If we advertise it as supported, Xvnc can send pointer updates in the middle of the string of rectangles. Federico |
From: Federico M. Q. <fed...@no...> - 2008-12-20 04:25:20
|
On Thu, 2008-12-18 at 16:27 +0000, Daniel P. Berrange wrote: > > - uint16_t n_rects; > > + int n_rects; > > Why this change ? THe value being read is an unsigned int16 With LastRect encoding, the server sends n_rects=65535. So, the condition in the "for" loop is always true as the counter could wrap around. Making it an int makes it safe (even if the actual LastRect will break the loop at the right time). [I've had my share of overflowed shorts before, too, so I'm kind of paranoid about them :) ] Federico |
From: Anthony L. <an...@co...> - 2008-12-19 22:20:39
|
Daniel P. Berrange wrote: > On Wed, Dec 17, 2008 at 07:46:37PM -0600, Anthony Liguori wrote: > > The former is securely authenticated and encryption, the latter is often > not - unless using the GTK-VNC + QEMU VeNCrypt extension, but I can well > imagine there's plenty of people who don't do that, particularly if they > are a SSH GSSAPI+Kerberos enabled environment. > > Both are valid deployment use cases and we shouldn't presume one vs the > other, although obviously we can make recommendations. > Also, this is why things like LBX and NX exist. X is a terrible protocol to use over high latency connections. These patches may make it as usable as TightVNC, but that still has to be pretty terrible. I don't mind the patches that adjust encoding order or implement new encodings. As long as it's in the spec, and we have evidence (via traces) that some servers behave better with a different encoding order, that's fine to me. Introducing low-level X dependencies seems like a bad idea to me though. It makes the code less portable because of platform specific hacks and it makes things generally less understandable. If there's wide agreement that this is something we should do, I'll concede, but it doesn't seem right to me. Regards, Anthony Liguori > Daniel > |
From: Anthony L. <an...@co...> - 2008-12-19 22:09:21
|
Federico Mena Quintero wrote: > On Wed, 2008-12-17 at 19:49 -0600, Anthony Liguori wrote: > >> This is a non-standard encoding and I don't see why it would be >> helpful. How does it change things from a server's perspective? >> > > Tight encoding is also non-standard ;) > > I was just matching what TightVNC does. > But it's at least reserved. Regards, Anthony Liguori > Federico > > |
From: Anthony L. <an...@co...> - 2008-12-19 22:09:06
|
Federico Mena Quintero wrote: > On Wed, 2008-12-17 at 19:48 -0600, Anthony Liguori wrote: > >> I don't believe this helps. >> >> If you are using virt-viewer, then you are using QEMU's VNC server. Our >> current ordering will do the right thing with QEMU's VNC server. >> >> How does this change what the server uses? >> > > Good question. For QEMU this indeed doesn't help (QEMU doesn't even > support tight encoding, last time I looked.) > > But when I was profiling things with Xvnc, it *did* help a lot. Xvnc > was sending a lot less data over the wire with these changes in. > How does it change what encodings are sent? Output from -gtk-vnc-debug would be helpful here. Regards, Anthony Liguori > Federico > > |
From: Anthony L. <an...@co...> - 2008-12-19 22:08:13
|
Daniel P. Berrange wrote: > On Wed, Dec 17, 2008 at 07:46:37PM -0600, Anthony Liguori wrote: > >> Federico Mena Quintero wrote: >> >>> Hi, everyone, >>> >>> I mentioned in #virt a few weeks ago that I was working on making >>> gtk-vnc be nominally as fast as TightVNC. This came out from an >>> Important Customer(tm) who wanted to use virt-viewer, but who found it >>> to be too slow. >>> >>> It turns out that they were on a crazy setup with a high-latency remote >>> X connection. My patches implement some tricks from TightVNC to handle >>> such connections: >>> >>> >> Can I ask, why in the world is your Important Customer(tm) forwarding >> gtk-vnc over SSH via X instead of doing VNC over X? That would solve >> all of these problems. >> > > The former is securely authenticated and encryption, the latter is often > not - unless using the GTK-VNC + QEMU VeNCrypt extension, but I can well > imagine there's plenty of people who don't do that, particularly if they > are a SSH GSSAPI+Kerberos enabled environment. > You can forward the VNC traffic over SSH. > Both are valid deployment use cases and we shouldn't presume one vs the > other, although obviously we can make recommendations. > I'm not sure it's worth jumping through hoops to support high-latency connections between the X client and server. That seems counter productive to me. Regards, Anthony Liguori > Daniel > |
From: Hugh O. B. <hb...@re...> - 2008-12-18 21:22:07
|
On Thu, Dec 18, 2008 at 08:17:55PM +0000, Daniel P. Berrange wrote: > On Thu, Dec 18, 2008 at 10:08:25AM -0600, Federico Mena Quintero wrote: > > On Wed, 2008-12-17 at 19:51 -0600, Anthony Liguori wrote: > > > > [backing store] > > > > > > Is this just double buffering in GTK parlance? If you avoid disabling > > > double buffering, does that help? > > > > Nope, it's different. You can ask the X server to use backing store if > > possible --- if the server can save the contents of a window, it can > > avoid sending Expose events when the window is unobscured. That is, > > nothing goes over the wire in the ideal case. > > > > [This is similar to requesting "save-unders" for temporary windows, but > > it saves your actual contents, not the underlying contents.] > > Ok, I see how this can make a big difference for slow X connections. > Obviously it'll have a bit of a memory overhead in the X server > to maintain the backing store. > > ACk to the patch in principle, once its has been #ifdef'd to not hardcode > the use of GTK X backend on all platforms. > > Daniel Glad to see this going in, it will be very heplful on the oVirt cloud setup (slow console connections will be the rule rather than the exception). --Hugh |
From: Daniel P. B. <ber...@re...> - 2008-12-18 20:27:06
|
On Thu, Dec 18, 2008 at 10:04:59AM -0600, Federico Mena Quintero wrote: > On Wed, 2008-12-17 at 19:50 -0600, Anthony Liguori wrote: > > [Compress motion events with XCheckTypedWindowEvent() ] > > This will break the Windows build. > > Oops, sorry, I didn't realize that gtk-vnc was meant to compile on > Windows as well. > > Would a big fat #ifdef be sufficient here, or do you have some other > policy for supporting X-isms? Is there any macro available from GTK headers indicating what backend you're compiling with. If so, #ifdef GTK_X_BACKEND would be suitable Using #ifndef WIN32 isn't strictly correct, because someone could be using Linux + the framebuffer backend for GTK, etc Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| |
From: Daniel P. B. <ber...@re...> - 2008-12-18 20:24:29
|
On Wed, Dec 17, 2008 at 07:46:37PM -0600, Anthony Liguori wrote: > Federico Mena Quintero wrote: > > Hi, everyone, > > > > I mentioned in #virt a few weeks ago that I was working on making > > gtk-vnc be nominally as fast as TightVNC. This came out from an > > Important Customer(tm) who wanted to use virt-viewer, but who found it > > to be too slow. > > > > It turns out that they were on a crazy setup with a high-latency remote > > X connection. My patches implement some tricks from TightVNC to handle > > such connections: > > > > Can I ask, why in the world is your Important Customer(tm) forwarding > gtk-vnc over SSH via X instead of doing VNC over X? That would solve > all of these problems. The former is securely authenticated and encryption, the latter is often not - unless using the GTK-VNC + QEMU VeNCrypt extension, but I can well imagine there's plenty of people who don't do that, particularly if they are a SSH GSSAPI+Kerberos enabled environment. Both are valid deployment use cases and we shouldn't presume one vs the other, although obviously we can make recommendations. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| |
From: Daniel P. B. <ber...@re...> - 2008-12-18 20:20:58
|
On Mon, Nov 24, 2008 at 02:40:42PM -0600, Federico Mena Quintero wrote: > * src/gvnc.c (gvnc_framebuffer_update): Integrate > Daniel Berrange's patch from Fedora to avoid painting on VNC requests > that do not really refer to framebuffer updates. > > Signed-off-by: Federico Mena Quintero <fed...@no...> I have already applide this patch & it was in 0.3.8 release What tree did you generate your patches against ? Our current HG tip is at http://freehg.org/u/aliguori/gtk-vnc.hg/ Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| |