[patch] mslogon
- From: Jonh Wendell <jwendell gnome org>
- To: gtk-vnc-devel List <gtk-vnc-list gnome org>
- Subject: [patch] mslogon
- Date: Wed, 15 Apr 2009 23:18:18 -0300
Hi, folks.
After my initial draft[0] to have this feature implemented, here is my
second attempt. Now it's based on Daniel's rewrite of Diffie-Hellman
implementation, using gnutls (LGPL) functions.
Today I debugged Dan's patch and found out what was crashing my UltraVNC
server: gcry_mpi_print() uses big-endian format, while the format
expected is little endian. I just created a convert() function which
does the conversion, in dh.c.
I tested it and it worked fine in vinagre :-)
[0]-http://mail.gnome.org/archives/gtk-vnc-list/2008-October/msg00000.html
--
Jonh Wendell
http://www.bani.com.br
diff --git a/src/Makefile.am b/src/Makefile.am
index df93e21..e2c1bbd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,7 @@ gtk_vnc_include_HEADERS = vncdisplay.h
libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h \
coroutine.h \
d3des.h d3des.c \
+ dh.h dh.c \
gvnc.h gvnc.c \
vncdisplay.h vncdisplay.c \
vncmarshal.h vncmarshal.c \
diff --git a/src/dh.c b/src/dh.c
new file mode 100644
index 0000000..2df5035
--- /dev/null
+++ b/src/dh.c
@@ -0,0 +1,159 @@
+/*
+ * GTK VNC Widget, Diffie Hellman
+ *
+ * Copyright (C) 2008 Red Hat, Inc
+ *
+ * Derived from gnutls_dh.c, also under:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "dh.h"
+#include "utils.h"
+
+/*
+ * General plan, as per gnutls_dh.c
+ *
+ *
+ * VNC server: X = g ^ x mod p;
+ * VNC client: Y = g ^ y mod p;
+ *
+ * Server key = Y ^ x mod p;
+ * Client key = X ^ y mod p;
+ *
+ * Where
+ * g == gen
+ * p == mod
+ *
+ * y == priv
+ * Y == pub
+ * Client key == key
+ *
+ *
+ */
+
+struct gvnc_dh {
+ gcry_mpi_t gen; /* g */
+ gcry_mpi_t mod; /* p */
+
+ gcry_mpi_t priv; /* y */
+ gcry_mpi_t pub; /* Y = g ^ y mod p */
+
+ gcry_mpi_t key; /* X ^ y mod p */
+};
+
+#define GVNC_DH_MAX_BITS 31
+
+struct gvnc_dh *gvnc_dh_new(gcry_mpi_t gen, gcry_mpi_t mod)
+{
+ struct gvnc_dh *ret = g_new0(struct gvnc_dh, 1);
+
+ ret->gen = gcry_mpi_copy(gen);
+ ret->mod = gcry_mpi_copy(mod);
+
+ return ret;
+}
+
+
+gcry_mpi_t gvnc_dh_gen_secret(struct gvnc_dh *dh)
+{
+ if (!(dh->priv = gcry_mpi_new(GVNC_DH_MAX_BITS)))
+ abort();
+
+ do {
+ gcry_mpi_randomize (dh->priv, (GVNC_DH_MAX_BITS / 8) * 8, GCRY_STRONG_RANDOM);
+ } while (gcry_mpi_cmp_ui (dh->priv, 0) == 0);
+
+ if (!(dh->pub = gcry_mpi_new(GVNC_DH_MAX_BITS)))
+ abort();
+
+ gcry_mpi_powm(dh->pub, dh->gen, dh->priv, dh->mod);
+
+ return dh->pub;
+}
+
+gcry_mpi_t gvnc_dh_gen_key(struct gvnc_dh *dh, gcry_mpi_t inter)
+{
+ if (!(dh->key = gcry_mpi_new(GVNC_DH_MAX_BITS)))
+ abort();
+
+ gcry_mpi_powm(dh->key, inter, dh->priv, dh->mod);
+
+ return dh->key;
+}
+
+void gvnc_dh_free(struct gvnc_dh *dh)
+{
+ if (dh->key)
+ gcry_mpi_release(dh->key);
+ if (dh->pub)
+ gcry_mpi_release(dh->pub);
+ if (dh->priv)
+ gcry_mpi_release(dh->priv);
+ if (dh->mod)
+ gcry_mpi_release(dh->mod);
+ if (dh->gen)
+ gcry_mpi_release(dh->gen);
+ g_free(dh);
+}
+
+/* convert from big-endian to little-endian:
+ 68 183 219 160 0 0 0 0 becomes
+ 0 0 0 0 68 183 219 160 */
+static void convert (unsigned char *input, int size)
+{
+ int i, count=0;
+
+ for (i = size-1; i >= 0; i--)
+ if (input[i] == 0)
+ count++;
+ else
+ break;
+
+ for (i = 0; i< size-count; i++)
+ {
+ input[i+count] = input[i];
+ input[i] = 0;
+ }
+}
+
+void gvnc_mpi_to_bytes(const gcry_mpi_t value, guchar* result)
+{
+ gcry_mpi_print(GCRYMPI_FMT_STD, result, 8, NULL, value);
+ convert (result, 8);
+}
+
+gcry_mpi_t gvnc_bytes_to_mpi(const guchar* value)
+{
+ gcry_mpi_t ret;
+ gcry_error_t error;
+
+ error = gcry_mpi_scan(&ret, GCRYMPI_FMT_STD, value, 8, NULL);
+ if (gcry_err_code (error) != GPG_ERR_NO_ERROR)
+ GVNC_DEBUG ("MPI error: %s\n", gcry_strerror (error));
+
+ return ret;
+}
+
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/src/dh.h b/src/dh.h
new file mode 100644
index 0000000..45e855f
--- /dev/null
+++ b/src/dh.h
@@ -0,0 +1,38 @@
+/*
+ * GTK VNC Widget, Diffie Hellman
+ *
+ * Copyright (C) 2008 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GTK_VNC_DH_H__
+#define GTK_VNC_DH_H__
+
+#include <glib.h>
+#include <gcrypt.h>
+
+struct gvnc_dh;
+
+struct gvnc_dh *gvnc_dh_new(gcry_mpi_t prime, gcry_mpi_t generator);
+
+gcry_mpi_t gvnc_dh_gen_secret(struct gvnc_dh *dh);
+gcry_mpi_t gvnc_dh_gen_key(struct gvnc_dh *dh, gcry_mpi_t inter);
+void gvnc_dh_free(struct gvnc_dh *dh);
+
+void gvnc_mpi_to_bytes(const gcry_mpi_t value, guchar* result);
+gcry_mpi_t gvnc_bytes_to_mpi(const guchar* value);
+
+#endif
diff --git a/src/gvnc.c b/src/gvnc.c
index b9ccbfe..cf885aa 100644
--- a/src/gvnc.c
+++ b/src/gvnc.c
@@ -51,6 +51,7 @@
#include <gdk/gdkkeysyms.h>
#include "getaddrinfo.h"
+#include "dh.h"
/* AI_ADDRCONFIG is missing on some systems and gnulib won't provide it
even if its emulated getaddrinfo() for us . */
@@ -2172,6 +2173,83 @@ static gboolean gvnc_perform_auth_vnc(struct gvnc *gvnc)
return gvnc_check_auth_result(gvnc);
}
+/*
+ * marscha 2006 - Martin Scharpf
+ * Encrypt bytes[length] in memory using key.
+ * Key has to be 8 bytes, length a multiple of 8 bytes.
+ */
+static void
+vncEncryptBytes2(unsigned char *where, const int length, unsigned char *key) {
+ int i, j;
+ deskey(key, EN0);
+ for (i = 0; i< 8; i++)
+ where[i] ^= key[i];
+ des(where, where);
+ for (i = 8; i < length; i += 8) {
+ for (j = 0; j < 8; j++)
+ where[i + j] ^= where[i + j - 8];
+ des(where + i, where + i);
+ }
+}
+
+static gboolean gvnc_perform_auth_mslogon(struct gvnc *gvnc)
+{
+ struct gvnc_dh *dh;
+ guchar gen[8], mod[8], resp[8], pub[8], key[8];
+ gcry_mpi_t genmpi, modmpi, respmpi, pubmpi, keympi;
+ guchar username[256], password[64];
+ guint passwordLen, usernameLen;
+
+ GVNC_DEBUG("Do Challenge\n");
+ if (!gvnc->cred_username)
+ return FALSE;
+ if (!gvnc->cred_password)
+ return FALSE;
+
+ gvnc_read(gvnc, gen, sizeof(gen));
+ gvnc_read(gvnc, mod, sizeof(mod));
+ gvnc_read(gvnc, resp, sizeof(resp));
+
+ genmpi = gvnc_bytes_to_mpi(gen);
+ modmpi = gvnc_bytes_to_mpi(mod);
+ respmpi = gvnc_bytes_to_mpi(resp);
+
+ dh = gvnc_dh_new(genmpi, modmpi);
+
+ pubmpi = gvnc_dh_gen_secret(dh);
+ gvnc_mpi_to_bytes(pubmpi, pub);
+
+ gvnc_write(gvnc, pub, sizeof(pub));
+
+ keympi = gvnc_dh_gen_key(dh, respmpi);
+ gvnc_mpi_to_bytes(keympi, key);
+
+ passwordLen = strlen(gvnc->cred_password);
+ usernameLen = strlen(gvnc->cred_username);
+ if (passwordLen > sizeof(password))
+ passwordLen = sizeof(password);
+ if (usernameLen > sizeof(username))
+ usernameLen = sizeof(username);
+
+ memset(password, 0, sizeof password);
+ memset(username, 0, sizeof username);
+ memcpy(password, gvnc->cred_password, passwordLen);
+ memcpy(username, gvnc->cred_username, usernameLen);
+
+ vncEncryptBytes2(username, sizeof(username), key);
+ vncEncryptBytes2(password, sizeof(password), key);
+
+ gvnc_write(gvnc, username, sizeof(username));
+ gvnc_write(gvnc, password, sizeof(password));
+ gvnc_flush(gvnc);
+
+ gcry_mpi_release(genmpi);
+ gcry_mpi_release(modmpi);
+ gcry_mpi_release(respmpi);
+ gvnc_dh_free (dh);
+
+ return gvnc_check_auth_result(gvnc);
+}
static gboolean gvnc_start_tls(struct gvnc *gvnc, int anonTLS)
{
@@ -2297,6 +2375,9 @@ gboolean gvnc_wants_credential_password(struct gvnc *gvnc)
return TRUE;
}
+ if (gvnc->auth_type == GVNC_AUTH_MSLOGON)
+ return TRUE;
+
return FALSE;
}
@@ -2309,6 +2390,9 @@ gboolean gvnc_wants_credential_username(struct gvnc *gvnc)
return TRUE;
}
+ if (gvnc->auth_type == GVNC_AUTH_MSLOGON)
+ return TRUE;
+
return FALSE;
}
@@ -2626,6 +2710,9 @@ static gboolean gvnc_perform_auth(struct gvnc *gvnc)
case GVNC_AUTH_VENCRYPT:
return gvnc_perform_auth_vencrypt(gvnc);
+ case GVNC_AUTH_MSLOGON:
+ return gvnc_perform_auth_mslogon(gvnc);
+
default:
if (gvnc->ops.auth_unsupported)
gvnc->ops.auth_unsupported (gvnc->ops_data, gvnc->auth_type);
@@ -2994,6 +3081,7 @@ gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type)
}
if (type != GVNC_AUTH_NONE &&
type != GVNC_AUTH_VNC &&
+ type != GVNC_AUTH_MSLOGON &&
type != GVNC_AUTH_TLS &&
type != GVNC_AUTH_VENCRYPT) {
if (gvnc->ops.auth_unsupported)
diff --git a/src/gvnc.h b/src/gvnc.h
index dc65128..496f747 100644
--- a/src/gvnc.h
+++ b/src/gvnc.h
@@ -128,7 +128,8 @@ typedef enum {
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_MSLOGON = 0xfffffffa /* Used by UltraVNC */
} gvnc_auth;
typedef enum {
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 6c608ca..a74494f 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -1910,6 +1910,7 @@ static void vnc_display_init(VncDisplay *display)
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));
+ priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_MSLOGON));
priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_VNC));
priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_NONE));
[Date Prev][
Date Next] [Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]