[gtk-vnc-devel] PATCH: Authentication API
- From: "Daniel P. Berrange" <berrange redhat com>
- To: gtk-vnc-devel <gtk-vnc-devel lists sourceforge net>
- Subject: [gtk-vnc-devel] PATCH: Authentication API
- Date: Fri, 20 Jul 2007 02:40:25 +0100
This patch adds a method for requesting authentication credentials from
the end application. This time around all the credentials are asked for
at once. The signal 'vnc-auth-credential' has a parameter which is a
GValueArray, this in turn contains GEnumValues. A little tedious, but it
marshalls well into python & this is just the way GTK likes to do arrays.
The example programs are re-done so that they dynamically build up a
dialog box to request all credentials at once.
examples/gvncviewer.c | 68 +++++-
examples/gvncviewer.py | 35 +++
src/gvnc.c | 498 +++++++++++++++++++++++++++++++++------------
src/gvnc.h | 36 +++
src/libgtk-vnc_sym.version | 5
src/vncdisplay.c | 127 ++++++++++-
src/vncdisplay.h | 11
src/vncmodule.c | 2
8 files changed, 645 insertions(+), 137 deletions(-)
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
diff -r d5a758344261 examples/gvncviewer.c
--- a/examples/gvncviewer.c Thu Jul 19 21:22:05 2007 -0400
+++ b/examples/gvncviewer.c Thu Jul 19 21:31:34 2007 -0400
@@ -81,6 +81,69 @@ static void send_cab(GtkWidget *menu G_G
guint keys[] = { GDK_Control_L, GDK_Alt_L, GDK_BackSpace };
printf("Sending Ctrl+Alt+Backspace\n");
vnc_display_send_keys(VNC_DISPLAY(vnc), keys, sizeof(keys)/sizeof(keys[0]));
+}
+
+static void vnc_credential(GtkWidget *vnc, GValueArray *credList)
+{
+ GtkWidget *dialog, **label, **entry, *box, *vbox;
+ int response;
+ unsigned int i;
+
+ printf("Got credential request for %d credential(s)\n", credList->n_values);
+
+ dialog = gtk_dialog_new_with_buttons("Authentication required",
+ NULL,
+ 0,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK,
+ NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+
+ box = gtk_table_new(credList->n_values, 2, FALSE);
+ label = g_new(GtkWidget *, credList->n_values);
+ entry = g_new(GtkWidget *, credList->n_values);
+
+ for (i = 0 ; i < credList->n_values ; i++) {
+ GValue *cred = g_value_array_get_nth(credList, i);
+ int credType = g_value_get_enum(cred);
+ switch (credType) {
+ case VNC_DISPLAY_CREDENTIAL_USERNAME:
+ label[i] = gtk_label_new("Username:");
+ break;
+ default:
+ label[i] = gtk_label_new("Password:");
+ break;
+ }
+ entry[i] = gtk_entry_new();
+
+ gtk_table_attach(GTK_TABLE(box), label[i], 0, 1, i, i+1, GTK_SHRINK, GTK_SHRINK, 3, 3);
+ gtk_table_attach(GTK_TABLE(box), entry[i], 1, 2, i, i+1, GTK_SHRINK, GTK_SHRINK, 3, 3);
+ }
+
+
+ vbox = gtk_bin_get_child(GTK_BIN(dialog));
+
+ gtk_container_add(GTK_CONTAINER(vbox), box);
+
+ gtk_widget_show_all(dialog);
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_hide(GTK_WIDGET(dialog));
+
+ if (response == GTK_RESPONSE_OK) {
+ for (i = 0 ; i < credList->n_values ; i++) {
+ GValue *cred = g_value_array_get_nth(credList, i);
+ int credType = g_value_get_enum(cred);
+ const char *data = gtk_entry_get_text(GTK_ENTRY(entry[i]));
+ vnc_display_set_credential(VNC_DISPLAY(vnc), credType, data);
+ }
+ } else {
+ printf("Aborting connection\n");
+ vnc_display_close(VNC_DISPLAY(vnc));
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(dialog));
}
int main(int argc, char **argv)
@@ -135,7 +198,7 @@ int main(int argc, char **argv)
gtk_widget_realize(vnc);
if (argc == 3)
- vnc_display_set_password(VNC_DISPLAY(vnc), argv[2]);
+ vnc_display_set_credential(VNC_DISPLAY(vnc), VNC_DISPLAY_CREDENTIAL_PASSWORD, argv[2]);
snprintf(hostname, sizeof(hostname), "%s", argv[1]);
display = strchr(hostname, ':');
@@ -159,7 +222,8 @@ int main(int argc, char **argv)
GTK_SIGNAL_FUNC(vnc_initialized), window);
gtk_signal_connect(GTK_OBJECT(vnc), "vnc-disconnected",
GTK_SIGNAL_FUNC(vnc_disconnected), NULL);
-
+ g_signal_connect(GTK_OBJECT(vnc), "vnc-auth-credential",
+ GTK_SIGNAL_FUNC(vnc_credential), NULL);
gtk_signal_connect(GTK_OBJECT(vnc), "vnc-pointer-grab",
GTK_SIGNAL_FUNC(vnc_grab), window);
diff -r d5a758344261 examples/gvncviewer.py
--- a/examples/gvncviewer.py Thu Jul 19 21:22:05 2007 -0400
+++ b/examples/gvncviewer.py Thu Jul 19 21:22:07 2007 -0400
@@ -51,6 +51,38 @@ def send_cab(src, vnc):
print "Send Ctrl+Alt+BackSpace"
vnc.send_keys(["Control_L", "Alt_L", "BackSpace"])
+def vnc_auth_cred(src, credList):
+ dialog = gtk.Dialog("Authentication required", None, 0, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
+ label = []
+ entry = []
+
+ box = gtk.Table(2, len(credList))
+
+ for i in range(len(credList)):
+ if credList[i] == gtkvnc.CREDENTIAL_USERNAME:
+ label.append(gtk.Label("Username:"))
+ else:
+ label.append(gtk.Label("Password:"))
+ entry.append(gtk.Entry())
+
+ box.attach(label[i], 0, 1, i, i+1, 0, 0, 3, 3)
+ box.attach(entry[i], 1, 2, i, i+1, 0, 0, 3, 3)
+
+ vbox = dialog.get_child()
+ vbox.add(box)
+
+ dialog.show_all()
+ res = dialog.run()
+ dialog.hide()
+
+ if res == gtk.RESPONSE_OK:
+ for i in range(len(credList)):
+ data = entry[i].get_text()
+ src.set_credential(credList[i], data)
+ else:
+ src.close()
+ dialog.destroy()
+
window = gtk.Window()
vnc = gtkvnc.Display()
@@ -89,7 +121,7 @@ vnc.set_keyboard_grab(True)
#v.set_pointer_local(True)
if len(sys.argv) == 3:
- vnc.set_password(sys.argv[2])
+ vnc.set_credential(gtkvnc.CREDENTIAL_PASSWORD, sys.argv[3])
disp = sys.argv[1].find(":")
if disp != -1:
@@ -107,5 +139,6 @@ vnc.connect("vnc-connected", vnc_connect
vnc.connect("vnc-connected", vnc_connected)
vnc.connect("vnc-initialized", vnc_initialized, window)
vnc.connect("vnc-disconnected", vnc_disconnected)
+vnc.connect("vnc-auth-credential", vnc_auth_cred)
gtk.main()
diff -r d5a758344261 src/gvnc.c
--- a/src/gvnc.c Thu Jul 19 21:22:05 2007 -0400
+++ b/src/gvnc.c Thu Jul 19 21:22:44 2007 -0400
@@ -38,57 +38,12 @@
#define KEY_FILE "key.pem"
#define CERT_FILE "cert.pem"
-static gboolean g_io_wait_helper(GIOChannel *channel G_GNUC_UNUSED,
- GIOCondition cond,
- gpointer data)
-{
- struct coroutine *to = data;
- yieldto(to, &cond);
- return FALSE;
-}
-
-static GIOCondition g_io_wait(GIOChannel *channel, GIOCondition cond)
-{
- GIOCondition *ret;
-
- g_io_add_watch(channel, cond, g_io_wait_helper, coroutine_self());
- ret = yield(NULL);
-
- return *ret;
-}
-
struct wait_queue
{
gboolean waiting;
struct coroutine *context;
};
-static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
- GIOChannel *channel,
- GIOCondition cond)
-{
- GIOCondition *ret;
- gint id;
-
- wait->context = coroutine_self();
- id = g_io_add_watch(channel, cond, g_io_wait_helper, wait->context);
-
- wait->waiting = TRUE;
- ret = yield(NULL);
- wait->waiting = FALSE;
-
- if (ret == NULL) {
- g_source_remove(id);
- return 0;
- } else
- return *ret;
-}
-
-static void g_io_wakeup(struct wait_queue *wait)
-{
- if (wait->waiting)
- yieldto(wait->context, NULL);
-}
typedef void gvnc_blt_func(struct gvnc *, uint8_t *, int, int, int, int, int);
@@ -96,6 +51,25 @@ typedef void gvnc_hextile_func(struct gv
uint16_t x, uint16_t y,
uint16_t width, uint16_t height,
uint8_t *fg, uint8_t *bg);
+
+/*
+ * A special GSource impl which allows us to wait on a certain
+ * condition to be satisified. This is effectively a boolean test
+ * run on each iteration of the main loop. So whenever a file has
+ * new I/O, or a timer occurrs, etc we'll do the check. This is
+ * pretty efficient compared to a normal GLib Idle func which has
+ * to busy wait on a timeout, since our condition is only checked
+ * when some other source's state changes
+ */
+typedef gboolean (*g_condition_wait_func)(gpointer);
+
+struct g_condition_wait_source
+{
+ GSource src;
+ struct coroutine *co;
+ g_condition_wait_func func;
+ gpointer data;
+};
struct gvnc
{
@@ -113,6 +87,12 @@ struct gvnc
int minor;
gnutls_session_t tls_session;
+ /* Auth related params */
+ unsigned int auth_type;
+ unsigned int auth_subtype;
+ char *cred_username;
+ char *cred_password;
+
char read_buffer[4096];
size_t read_offset;
size_t read_size;
@@ -144,28 +124,6 @@ struct gvnc
int xmit_buffer_size;
};
-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,
- GVNC_AUTH_VENCRYPT = 19
-};
-
-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,
-};
-
#define DEBUG 0
#if DEBUG
@@ -183,6 +141,122 @@ static void debug_log(int level, const c
#define nibhi(a) (((a) >> 4) & 0x0F)
#define niblo(a) ((a) & 0x0F)
+
+/* Main loop helper functions */
+static gboolean g_io_wait_helper(GIOChannel *channel G_GNUC_UNUSED,
+ GIOCondition cond,
+ gpointer data)
+{
+ struct coroutine *to = data;
+ yieldto(to, &cond);
+ return FALSE;
+}
+
+static GIOCondition g_io_wait(GIOChannel *channel, GIOCondition cond)
+{
+ GIOCondition *ret;
+
+ g_io_add_watch(channel, cond, g_io_wait_helper, coroutine_self());
+ ret = yield(NULL);
+
+ return *ret;
+}
+
+
+static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
+ GIOChannel *channel,
+ GIOCondition cond)
+{
+ GIOCondition *ret;
+ gint id;
+
+ wait->context = coroutine_self();
+ id = g_io_add_watch(channel, cond, g_io_wait_helper, wait->context);
+
+ wait->waiting = TRUE;
+ ret = yield(NULL);
+ wait->waiting = FALSE;
+
+ if (ret == NULL) {
+ g_source_remove(id);
+ return 0;
+ } else
+ return *ret;
+}
+
+static void g_io_wakeup(struct wait_queue *wait)
+{
+ if (wait->waiting)
+ yieldto(wait->context, NULL);
+}
+
+
+/*
+ * Call immediately before the main loop does an iteration. Returns
+ * true if the condition we're checking is ready for dispatch
+ */
+static gboolean g_condition_wait_prepare(GSource *src,
+ int *timeout) {
+ struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
+ *timeout = -1;
+ return vsrc->func(vsrc->data);
+}
+
+/*
+ * Call immediately after the main loop does an iteration. Returns
+ * true if the condition we're checking is ready for dispatch
+ */
+static gboolean g_condition_wait_check(GSource *src) {
+ struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
+ return vsrc->func(vsrc->data);
+}
+
+static gboolean g_condition_wait_dispatch(GSource *src G_GNUC_UNUSED,
+ GSourceFunc cb,
+ gpointer data) {
+ return cb(data);
+}
+
+GSourceFuncs waitFuncs = {
+ .prepare = g_condition_wait_prepare,
+ .check = g_condition_wait_check,
+ .dispatch = g_condition_wait_dispatch,
+ };
+
+static gboolean g_condition_wait_helper(gpointer data)
+{
+ struct coroutine *co = (struct coroutine *)data;
+ yieldto(co, NULL);
+ return FALSE;
+}
+
+static gboolean g_condition_wait(g_condition_wait_func func, gpointer data)
+{
+ GSource *src;
+ struct g_condition_wait_source *vsrc;
+
+ /* Short-circuit check in case we've got it ahead of time */
+ if (func(data)) {
+ return TRUE;
+ }
+
+ /*
+ * Don't have it, so yield to the main loop, checking the condition
+ * on each iteration of the main loop
+ */
+ src = g_source_new(&waitFuncs, sizeof(struct g_condition_wait_source));
+ vsrc = (struct g_condition_wait_source *)src;
+
+ vsrc->func = func;
+ vsrc->data = data;
+ vsrc->co = coroutine_self();
+
+ g_source_attach(src, NULL);
+ g_source_set_callback(src, g_condition_wait_helper, coroutine_self(), NULL);
+ yield(NULL);
+ return TRUE;
+}
+
/* IO functions */
@@ -912,7 +986,8 @@ static void gvnc_update(struct gvnc *gvn
{
if (gvnc->has_error || !gvnc->ops.update)
return;
- gvnc->has_error = !gvnc->ops.update(gvnc->ops_data, x, y, width, height);
+ if (!gvnc->ops.update(gvnc->ops_data, x, y, width, height))
+ gvnc->has_error = TRUE;
}
static void gvnc_set_color_map_entry(struct gvnc *gvnc, uint16_t color,
@@ -921,15 +996,17 @@ static void gvnc_set_color_map_entry(str
{
if (gvnc->has_error || !gvnc->ops.set_color_map_entry)
return;
- gvnc->has_error = !gvnc->ops.set_color_map_entry(gvnc->ops_data, color,
- red, green, blue);
+ if (!gvnc->ops.set_color_map_entry(gvnc->ops_data, color,
+ red, green, blue))
+ gvnc->has_error = TRUE;
}
static void gvnc_bell(struct gvnc *gvnc)
{
if (gvnc->has_error || !gvnc->ops.bell)
return;
- gvnc->has_error = !gvnc->ops.bell(gvnc->ops_data);
+ if (!gvnc->ops.bell(gvnc->ops_data))
+ gvnc->has_error = TRUE;
}
static void gvnc_server_cut_text(struct gvnc *gvnc, const void *data,
@@ -937,28 +1014,32 @@ static void gvnc_server_cut_text(struct
{
if (gvnc->has_error || !gvnc->ops.server_cut_text)
return;
- gvnc->has_error = !gvnc->ops.server_cut_text(gvnc->ops_data, data, len);
+ if (!gvnc->ops.server_cut_text(gvnc->ops_data, data, len))
+ gvnc->has_error = TRUE;
}
static void gvnc_resize(struct gvnc *gvnc, int width, int height)
{
if (gvnc->has_error || !gvnc->ops.resize)
return;
- gvnc->has_error = !gvnc->ops.resize(gvnc->ops_data, width, height);
+ if (!gvnc->ops.resize(gvnc->ops_data, width, height))
+ gvnc->has_error = TRUE;
}
static void gvnc_pointer_type_change(struct gvnc *gvnc, int absolute)
{
if (gvnc->has_error || !gvnc->ops.pointer_type_change)
return;
- gvnc->has_error = !gvnc->ops.pointer_type_change(gvnc->ops_data, absolute);
+ if (!gvnc->ops.pointer_type_change(gvnc->ops_data, absolute))
+ gvnc->has_error = TRUE;
}
static void gvnc_shared_memory_rmid(struct gvnc *gvnc, int shmid)
{
if (gvnc->has_error || !gvnc->ops.shared_memory_rmid)
return;
- gvnc->has_error = !gvnc->ops.shared_memory_rmid(gvnc->ops_data, shmid);
+ if (!gvnc->ops.shared_memory_rmid(gvnc->ops_data, shmid))
+ gvnc->has_error = TRUE;
}
static void gvnc_framebuffer_update(struct gvnc *gvnc, int32_t etype,
@@ -1125,19 +1206,19 @@ static gboolean gvnc_check_auth_result(s
return FALSE;
}
-static gboolean gvnc_perform_auth_vnc(struct gvnc *gvnc, const char *password)
+static gboolean gvnc_perform_auth_vnc(struct gvnc *gvnc)
{
uint8_t challenge[16];
uint8_t key[8];
GVNC_DEBUG("Do Challenge\n");
- if (!password)
+ if (!gvnc->cred_password)
return FALSE;
gvnc_read(gvnc, challenge, 16);
memset(key, 0, 8);
- strncpy((char*)key, (char*)password, 8);
+ strncpy((char*)key, (char*)gvnc->cred_password, 8);
deskey(key, EN0);
des(challenge, challenge);
@@ -1245,9 +1326,82 @@ static gboolean gvnc_start_tls(struct gv
}
}
-static gboolean gvnc_perform_auth_vencrypt(struct gvnc *gvnc, const char *password)
-{
- int major, minor, status, wantAuth = GVNC_AUTH_INVALID, anonTLS;
+gboolean gvnc_wants_credential_password(struct gvnc *gvnc)
+{
+ if (gvnc->auth_type == 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;
+}
+
+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;
+ 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)
+ return FALSE;
+ return TRUE;
+}
+
+
+static gboolean gvnc_perform_auth_vencrypt(struct gvnc *gvnc)
+{
+ int major, minor, status, anonTLS;
unsigned int nauth, i;
unsigned int auth[20];
@@ -1283,41 +1437,48 @@ static gboolean gvnc_perform_auth_vencry
GVNC_DEBUG("Possible auth %d\n", auth[i]);
}
+ if (gvnc->has_error || !gvnc->ops.auth_subtype)
+ return FALSE;
+
+ if (!gvnc->ops.auth_subtype(gvnc->ops_data, nauth, auth))
+ gvnc->has_error = TRUE;
if (gvnc->has_error)
return FALSE;
- for (i = 0 ; i < nauth ; i++) {
- if (auth[i] == GVNC_AUTH_VENCRYPT_TLSNONE ||
- auth[i] == GVNC_AUTH_VENCRYPT_TLSPLAIN ||
- auth[i] == GVNC_AUTH_VENCRYPT_TLSVNC ||
- auth[i] == GVNC_AUTH_VENCRYPT_X509NONE ||
- auth[i] == GVNC_AUTH_VENCRYPT_X509PLAIN ||
- auth[i] == GVNC_AUTH_VENCRYPT_X509VNC) {
- wantAuth = auth[i];
- break;
- }
- }
-
- if (wantAuth == GVNC_AUTH_VENCRYPT_PLAIN) {
+ 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;
+
+#if !DEBUG
+ if (gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_PLAIN) {
GVNC_DEBUG("Cowardly refusing to transmit plain text password\n");
return FALSE;
}
-
- GVNC_DEBUG("Choose auth %d\n", wantAuth);
- gvnc_write_u32(gvnc, wantAuth);
+#endif
+
+ gvnc_write_u32(gvnc, gvnc->auth_subtype);
gvnc_flush(gvnc);
status = gvnc_read_u8(gvnc);
if (status != 1) {
- GVNC_DEBUG("Server refused VeNCrypt auth %d %d\n", wantAuth, status);
- return FALSE;
- }
-
- if (wantAuth == GVNC_AUTH_VENCRYPT_TLSNONE ||
- wantAuth == GVNC_AUTH_VENCRYPT_TLSPLAIN ||
- wantAuth == GVNC_AUTH_VENCRYPT_TLSVNC)
+ 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:
anonTLS = 1;
- else
+ break;
+ default:
anonTLS = 0;
+ }
if (!gvnc_start_tls(gvnc, anonTLS)) {
GVNC_DEBUG("Could not start TLS\n");
@@ -1325,7 +1486,7 @@ static gboolean gvnc_perform_auth_vencry
}
GVNC_DEBUG("Completed TLS setup\n");
- switch (wantAuth) {
+ switch (gvnc->auth_subtype) {
/* Plain certificate based auth */
case GVNC_AUTH_VENCRYPT_TLSNONE:
case GVNC_AUTH_VENCRYPT_X509NONE:
@@ -1336,16 +1497,26 @@ static gboolean gvnc_perform_auth_vencry
case GVNC_AUTH_VENCRYPT_TLSVNC:
case GVNC_AUTH_VENCRYPT_X509VNC:
GVNC_DEBUG("Handing off to VNC auth\n");
- return gvnc_perform_auth_vnc(gvnc, password);
+ return gvnc_perform_auth_vnc(gvnc);
default:
return FALSE;
}
}
-static gboolean gvnc_perform_auth(struct gvnc *gvnc, const char *password)
-{
- int wantAuth = GVNC_AUTH_INVALID;
+static gboolean gvnc_has_auth_type(gpointer data)
+{
+ struct gvnc *gvnc = (struct gvnc *)data;
+
+ if (gvnc->has_error)
+ return TRUE;
+ if (gvnc->auth_type == GVNC_AUTH_INVALID)
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean gvnc_perform_auth(struct gvnc *gvnc)
+{
unsigned int nauth, i;
unsigned int auth[10];
@@ -1372,34 +1543,38 @@ static gboolean gvnc_perform_auth(struct
GVNC_DEBUG("Possible auth %d\n", auth[i]);
}
+ if (gvnc->has_error || !gvnc->ops.auth_type)
+ return FALSE;
+
+ if (!gvnc->ops.auth_type(gvnc->ops_data, nauth, auth))
+ gvnc->has_error = TRUE;
if (gvnc->has_error)
return FALSE;
- for (i = 0 ; i < nauth ; i++) {
- if (auth[i] == GVNC_AUTH_NONE ||
- auth[i] == GVNC_AUTH_VNC ||
- auth[i] == GVNC_AUTH_VENCRYPT) {
- wantAuth = auth[i];
- break;
- }
- }
+ GVNC_DEBUG("Waiting for auth type\n");
+ g_condition_wait(gvnc_has_auth_type, gvnc);
+ if (gvnc->has_error)
+ return FALSE;
+
+ GVNC_DEBUG("Choose auth %d\n", gvnc->auth_type);
+ if (gvnc_gather_credentials(gvnc))
+ return FALSE;
if (gvnc->minor > 6) {
- GVNC_DEBUG("Chose auth %d\n", wantAuth);
- gvnc_write_u8(gvnc, wantAuth);
+ gvnc_write_u8(gvnc, gvnc->auth_type);
gvnc_flush(gvnc);
}
- switch (wantAuth) {
+ switch (gvnc->auth_type) {
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, password);
+ return gvnc_perform_auth_vnc(gvnc);
case GVNC_AUTH_VENCRYPT:
- return gvnc_perform_auth_vencrypt(gvnc, password);
+ return gvnc_perform_auth_vencrypt(gvnc);
default:
return FALSE;
@@ -1419,6 +1594,8 @@ struct gvnc *gvnc_new(const struct gvnc_
memcpy(&gvnc->ops, ops, sizeof(*ops));
gvnc->ops_data = ops_data;
+ gvnc->auth_type = GVNC_AUTH_INVALID;
+ gvnc->auth_subtype = GVNC_AUTH_INVALID;
return gvnc;
}
@@ -1454,6 +1631,14 @@ void gvnc_close(struct gvnc *gvnc)
free(gvnc->name);
gvnc->name = NULL;
+
+ free(gvnc->cred_username);
+ gvnc->cred_username = NULL;
+ free(gvnc->cred_password);
+ gvnc->cred_password = NULL;
+
+ gvnc->auth_type = GVNC_AUTH_INVALID;
+ gvnc->auth_subtype = GVNC_AUTH_INVALID;
gvnc->has_error = 0;
}
@@ -1483,7 +1668,7 @@ gboolean gvnc_is_initialized(struct gvnc
}
-gboolean gvnc_initialize(struct gvnc *gvnc, gboolean shared_flag, const char *password)
+gboolean gvnc_initialize(struct gvnc *gvnc, gboolean shared_flag)
{
int ret;
char version[13];
@@ -1512,7 +1697,7 @@ gboolean gvnc_initialize(struct gvnc *gv
gvnc_flush(gvnc);
GVNC_DEBUG("Negotiated protocol %d %d\n", gvnc->major, gvnc->minor);
- if (!gvnc_perform_auth(gvnc, password)) {
+ if (!gvnc_perform_auth(gvnc)) {
GVNC_DEBUG("Auth failed\n");
goto fail;
}
@@ -1570,6 +1755,9 @@ gboolean gvnc_open_host(struct gvnc *gvn
int ret;
if (gvnc_is_open(gvnc))
return TRUE;
+
+ gvnc->host = g_strdup(host);
+ gvnc->port = g_strdup(port);
GVNC_DEBUG("Resolving host %s %s\n", host, port);
memset (&hints, '\0', sizeof (hints));
@@ -1631,6 +1819,66 @@ gboolean gvnc_open_host(struct gvnc *gvn
}
+gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type)
+{
+ GVNC_DEBUG("Requested auth type %d\n", 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_VENCRYPT) {
+ gvnc->has_error = TRUE;
+ return gvnc_has_error(gvnc);
+ }
+ 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)
+{
+ GVNC_DEBUG("Requested auth subtype %d\n", type);
+ if (gvnc->auth_type != GVNC_AUTH_VENCRYPT) {
+ gvnc->has_error = TRUE;
+ return gvnc_has_error(gvnc);
+ }
+ if (gvnc->auth_subtype != GVNC_AUTH_INVALID) {
+ gvnc->has_error = TRUE;
+ return gvnc_has_error(gvnc);
+ }
+ 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");
+ if (gvnc->cred_password)
+ free(gvnc->cred_password);
+ if (!(gvnc->cred_password = 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);
+ if (gvnc->cred_username)
+ free(gvnc->cred_username);
+ if (!(gvnc->cred_username = strdup(username))) {
+ gvnc->has_error = TRUE;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
gboolean gvnc_set_local(struct gvnc *gvnc, struct gvnc_framebuffer *fb)
{
diff -r d5a758344261 src/gvnc.h
--- a/src/gvnc.h Thu Jul 19 21:22:05 2007 -0400
+++ b/src/gvnc.h Thu Jul 19 21:22:07 2007 -0400
@@ -8,6 +8,9 @@ struct gvnc;
struct gvnc_ops
{
+ gboolean (*auth_cred)(void *);
+ gboolean (*auth_type)(void *, unsigned int, unsigned int *);
+ gboolean (*auth_subtype)(void *, unsigned int, unsigned int *);
gboolean (*update)(void *, int, int, int, int);
gboolean (*set_color_map_entry)(void *, int, int, int, int);
gboolean (*bell)(void *);
@@ -71,6 +74,29 @@ enum {
GVNC_ENCODING_SHARED_MEMORY = -258,
};
+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,
+ GVNC_AUTH_VENCRYPT = 19
+};
+
+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,
+};
+
+
struct gvnc *gvnc_new(const struct gvnc_ops *ops, gpointer ops_data);
void gvnc_free(struct gvnc *gvnc);
@@ -81,7 +107,15 @@ gboolean gvnc_open_host(struct gvnc *gvn
gboolean gvnc_open_host(struct gvnc *gvnc, const char *host, const char *port);
gboolean gvnc_is_open(struct gvnc *gvnc);
-gboolean gvnc_initialize(struct gvnc *gvnc, gboolean shared_flag, const char *password);
+gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type);
+gboolean gvnc_set_auth_subtype(struct gvnc *gvnc, unsigned int type);
+
+gboolean gvnc_set_credential_password(struct gvnc *gvnc, const char *password);
+gboolean gvnc_set_credential_username(struct gvnc *gvnc, const char *username);
+gboolean gvnc_wants_credential_password(struct gvnc *gvnc);
+gboolean gvnc_wants_credential_username(struct gvnc *gvnc);
+
+gboolean gvnc_initialize(struct gvnc *gvnc, gboolean shared_flag);
gboolean gvnc_is_initialized(struct gvnc *gvnc);
gboolean gvnc_server_message(struct gvnc *gvnc);
diff -r d5a758344261 src/libgtk-vnc_sym.version
--- a/src/libgtk-vnc_sym.version Thu Jul 19 21:22:05 2007 -0400
+++ b/src/libgtk-vnc_sym.version Thu Jul 19 21:22:07 2007 -0400
@@ -1,6 +1,8 @@
{
global:
vnc_display_get_type;
+ vnc_display_credential_get_type;
+
vnc_display_new;
vnc_display_open_fd;
vnc_display_open_host;
@@ -9,7 +11,8 @@
vnc_display_send_keys;
- vnc_display_set_password;
+ vnc_display_set_credential;
+
vnc_display_set_use_shm;
vnc_display_set_pointer_local;
vnc_display_set_pointer_grab;
diff -r d5a758344261 src/vncdisplay.c
--- a/src/vncdisplay.c Thu Jul 19 21:22:05 2007 -0400
+++ b/src/vncdisplay.c Thu Jul 19 21:22:07 2007 -0400
@@ -42,7 +42,6 @@ struct _VncDisplayPrivate
int button_mask;
int last_x;
int last_y;
- const char *password;
gboolean absolute;
@@ -63,12 +62,14 @@ enum
VNC_CONNECTED,
VNC_INITIALIZED,
VNC_DISCONNECTED,
+ VNC_AUTH_CREDENTIAL,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, 0, 0, 0,
- 0, 0, 0 };
+ 0, 0, 0, 0 };
+static GParamSpec *signalCredParam;
GtkWidget *vnc_display_new(void)
{
@@ -479,7 +480,73 @@ static gboolean on_shared_memory_rmid(vo
return TRUE;
}
+
+static gboolean on_auth_cred(void *opaque)
+{
+ VncDisplay *obj = VNC_DISPLAY(opaque);
+ GValueArray *credList;
+ GValue username, password;
+
+ memset(&username, 0, sizeof(username));
+ memset(&password, 0, sizeof(password));
+
+ credList = g_value_array_new(2);
+ if (gvnc_wants_credential_username(obj->priv->gvnc)) {
+ g_value_init(&username, G_PARAM_SPEC_VALUE_TYPE(signalCredParam));
+ g_value_set_enum(&username, VNC_DISPLAY_CREDENTIAL_USERNAME);
+ g_value_array_append(credList, &username);
+ }
+ if (gvnc_wants_credential_password(obj->priv->gvnc)) {
+ g_value_init(&password, G_PARAM_SPEC_VALUE_TYPE(signalCredParam));
+ g_value_set_enum(&password, VNC_DISPLAY_CREDENTIAL_PASSWORD);
+ g_value_array_append(credList, &password);
+ }
+
+ g_signal_emit (G_OBJECT (obj),
+ signals[VNC_AUTH_CREDENTIAL],
+ 0,
+ credList);
+
+ g_value_array_free(credList);
+
+ return TRUE;
+}
+
+static gboolean on_auth_type(void *opaque, unsigned int ntype, unsigned int *types)
+{
+ VncDisplay *obj = VNC_DISPLAY(opaque);
+ VncDisplayPrivate *priv = obj->priv;
+
+ /*
+ * XXX lame - we should have some prioritization. That
+ * said most servers only support 1 auth type at any time
+ */
+ if (ntype)
+ gvnc_set_auth_type(priv->gvnc, types[0]);
+
+ return TRUE;
+}
+
+static gboolean on_auth_subtype(void *opaque, unsigned int ntype, unsigned int *types)
+{
+ VncDisplay *obj = VNC_DISPLAY(opaque);
+ VncDisplayPrivate *priv = obj->priv;
+
+ /*
+ * XXX lame - we should have some prioritization. That
+ * said most servers only support 1 auth type at any time
+ */
+ if (ntype)
+ gvnc_set_auth_subtype(priv->gvnc, types[0]);
+
+ return TRUE;
+}
+
+
static const struct gvnc_ops vnc_display_ops = {
+ .auth_cred = on_auth_cred,
+ .auth_type = on_auth_type,
+ .auth_subtype = on_auth_subtype,
.update = on_update,
.resize = on_resize,
.pointer_type_change = on_pointer_type_change,
@@ -514,7 +581,7 @@ static void *vnc_coroutine(void *opaque)
signals[VNC_CONNECTED],
0);
- if (gvnc_initialize(priv->gvnc, FALSE, priv->password))
+ if (gvnc_initialize(priv->gvnc, FALSE))
goto cleanup;
g_signal_emit (G_OBJECT (obj),
@@ -627,6 +694,13 @@ static void vnc_display_class_init(VncDi
static void vnc_display_class_init(VncDisplayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ signalCredParam = g_param_spec_enum("credential",
+ "credential",
+ "credential",
+ vnc_display_credential_get_type(),
+ 0,
+ G_PARAM_READABLE);
signals[VNC_CONNECTED] =
g_signal_new ("vnc-connected",
@@ -657,6 +731,18 @@ static void vnc_display_class_init(VncDi
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
+
+ signals[VNC_AUTH_CREDENTIAL] =
+ g_signal_new ("vnc-auth-credential",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (VncDisplayClass, vnc_auth_credential),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__PARAM,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_VALUE_ARRAY);
+
signals[VNC_POINTER_GRAB] =
g_signal_new("vnc-pointer-grab",
@@ -753,9 +839,21 @@ static void vnc_display_init(GTypeInstan
display->priv->gvnc = gvnc_new(&vnc_display_ops, obj);
}
-void vnc_display_set_password(VncDisplay *obj, const gchar *password)
-{
- obj->priv->password = password;
+gboolean vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data)
+{
+ switch (type) {
+ case VNC_DISPLAY_CREDENTIAL_PASSWORD:
+ if (gvnc_set_credential_password(obj->priv->gvnc, data))
+ return FALSE;
+ return TRUE;
+
+ case VNC_DISPLAY_CREDENTIAL_USERNAME:
+ if (gvnc_set_credential_username(obj->priv->gvnc, data))
+ return FALSE;
+ return TRUE;
+ }
+
+ return FALSE;
}
void vnc_display_set_use_shm(VncDisplay *obj, gboolean enable)
@@ -819,6 +917,23 @@ GType vnc_display_get_type(void)
return type;
}
+
+GType vnc_display_credential_get_type(void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ { VNC_DISPLAY_CREDENTIAL_PASSWORD, "VNC_DISPLAY_CREDENTIAL_PASSWORD", "password" },
+ { VNC_DISPLAY_CREDENTIAL_USERNAME, "VNC_DISPLAY_CREDENTIAL_USERNAME", "username" },
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static ("VncDisplayCredentialType", values );
+ }
+
+ return etype;
+}
+
int vnc_display_get_width(VncDisplay *obj)
{
diff -r d5a758344261 src/vncdisplay.h
--- a/src/vncdisplay.h Thu Jul 19 21:22:05 2007 -0400
+++ b/src/vncdisplay.h Thu Jul 19 21:22:07 2007 -0400
@@ -19,6 +19,7 @@ typedef struct _VncDisplayPrivate VncDis
#include <glib.h>
#define VNC_TYPE_DISPLAY (vnc_display_get_type())
+#define VNC_TYPE_DISPLAY_CREDENTIAL (vnc_display_credential_get_type())
#define VNC_DISPLAY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), VNC_TYPE_DISPLAY, VncDisplay))
@@ -50,11 +51,19 @@ struct _VncDisplayClass
void (* vnc_connected) (VncDisplay *display);
void (* vnc_initialized) (VncDisplay *display);
void (* vnc_disconnected) (VncDisplay *display);
+ void (* vnc_auth_credential) (VncDisplay *display, GValueArray *credList);
};
+
+typedef enum
+{
+ VNC_DISPLAY_CREDENTIAL_PASSWORD,
+ VNC_DISPLAY_CREDENTIAL_USERNAME,
+} VncDisplayCredential;
G_BEGIN_DECLS
GType vnc_display_get_type(void);
+GType vnc_display_credential_get_type(void);
GtkWidget * vnc_display_new(void);
gboolean vnc_display_open_fd(VncDisplay *obj, int fd);
@@ -64,7 +73,7 @@ void vnc_display_close(VncDisplay *obj)
void vnc_display_send_keys(VncDisplay *obj, const guint *keyvals, int nkeyvals);
-void vnc_display_set_password(VncDisplay *obj, const gchar *password);
+gboolean vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data);
void vnc_display_set_use_shm(VncDisplay *obj, gboolean enable);
void vnc_display_set_pointer_local(VncDisplay *obj, gboolean enable);
diff -r d5a758344261 src/vncmodule.c
--- a/src/vncmodule.c Thu Jul 19 21:22:05 2007 -0400
+++ b/src/vncmodule.c Thu Jul 19 21:22:07 2007 -0400
@@ -21,6 +21,7 @@
#include <pygobject.h>
void gtkvnc_register_classes (PyObject *d);
+void gtkvnc_add_constants(PyObject *module, const gchar *strip_prefix);
extern PyMethodDef gtkvnc_functions[];
DL_EXPORT(void) initgtkvnc(void);
@@ -39,6 +40,7 @@ DL_EXPORT(void) initgtkvnc(void)
if (PyErr_Occurred())
Py_FatalError("can't get dict");
+ gtkvnc_add_constants(m, "VNC_DISPLAY_");
gtkvnc_register_classes (d);
if (PyErr_Occurred ()) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]