[gtk-vnc-devel] PATCH: Support for x509 credentials



When authenticating with TLS+x509, the GTK Widget needs 1-to-4 files

  - A CA certificate (compulsory)
  - A CA revocation list (optional)
  - A client certificate (compulsory IFF the server does client verification)
  - A client key (compulsory IFF the server does client verification)

For the latter two case, the client has no way of knowing if it needs to
provde them or not. The server, may or may not be doing client certificate
validation, and it may or may not fail auth if it does. So, if the client
has its own cert & key it should use them, if it doesn't then it may get
a auth rejection from the server later.

This is all a little complex and not nice to expose to application 
developers really. So I think I want to provide a simplified interface
to apps. For this purposes I am introducing a single credential type.
It is called 'VNC_CREDENTIAL_CLIENTNAME'.  The application should set
this to its short logical name - eg, 'gvncviewer'. When this is set the
vncdisplay class will lookup the certificate data in the following
locations

  - A CA certificate in:

     $HOME/.pki/CA/cacert.pem
     /etc/pki/CA/cacert.pem

  - A CA revocation list in:

     $HOME/.pki/CA/cacrl.pem
     /etc/pki/CA/cacrl.pem

  - A client key in

     $HOME/.pki/<CLIENTNAME>/private/clientkey.pem
     /etc/pki/<CLIENTNAME>/private/clientkey.pem

  - A client certificate in

     $HOME/.pki/<CLIENTNAME>/clientcert.pem
     /etc/pki/<CLIENTNAME>/clientcert.pem

In the future I'll probably also make it look for

     $HOME/.pki/<CLIENTNAME>/clientcert-[hostname].pem
     /etc/pki/<CLIENTNAME>/clientcert-[hostname].pem
     $HOME/.pki/<CLIENTNAME>/clientcert-[domainname].pem
     /etc/pki/<CLIENTNAME>/clientcert-[domainname].pem

To allow it to give different certs based on the server it is connecting
to. For now though the code is assuming all a user's server are under
the same CA realm.

I've re-done the authentication dialog for the demo programs to show 
how to handle this. They are a little more complex now, since you can not
assume that every credential the VNC widget asks for maps into a user
presentable text field.

Regards,
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 4c3599147f53 examples/gvncviewer.c
--- a/examples/gvncviewer.c	Mon Jul 30 20:12:10 2007 -0400
+++ b/examples/gvncviewer.c	Mon Jul 30 20:34:46 2007 -0400
@@ -96,65 +96,103 @@ static void send_cab(GtkWidget *menu G_G
 
 static void vnc_credential(GtkWidget *vnc, GValueArray *credList)
 {
-	GtkWidget *dialog, **label, **entry, *box, *vbox;
+	GtkWidget *dialog = NULL;
 	int response;
-	unsigned int i;
+	unsigned int i, prompt = 0;
+	const char **data;
 
 	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);
+	data = g_new0(const char *, 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) {
+		switch (g_value_get_enum(cred)) {
 		case VNC_DISPLAY_CREDENTIAL_USERNAME:
-			label[i] = gtk_label_new("Username:");
+		case VNC_DISPLAY_CREDENTIAL_PASSWORD:
+			prompt++;
 			break;
+		case VNC_DISPLAY_CREDENTIAL_CLIENTNAME:
+			data[i] = "gvncviewer";
 		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++) {
+	}
+
+	if (prompt) {
+		GtkWidget **label, **entry, *box, *vbox;
+		int row;
+		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 *, prompt);
+		entry = g_new(GtkWidget *, prompt);
+
+		for (i = 0, row =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));
+			switch (g_value_get_enum(cred)) {
+			case VNC_DISPLAY_CREDENTIAL_USERNAME:
+				label[row] = gtk_label_new("Username:");
+				break;
+			case VNC_DISPLAY_CREDENTIAL_PASSWORD:
+				label[row] = gtk_label_new("Password:");
+				break;
+			default:
+				continue;
+			}
+			entry[row] = gtk_entry_new();
+
+			gtk_table_attach(GTK_TABLE(box), label[i], 0, 1, row, row+1, GTK_SHRINK, GTK_SHRINK, 3, 3);
+			gtk_table_attach(GTK_TABLE(box), entry[i], 1, 2, row, row+1, GTK_SHRINK, GTK_SHRINK, 3, 3);
+			row++;
+		}
+
+		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, 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]));
+					break;
+				}
+			}
+		}
+	}
+
+	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(vnc),
+						       g_value_get_enum(cred),
+						       data[i])) {
+				printf("Failed to set credential type %d\n", g_value_get_enum(cred));
+				vnc_display_close(VNC_DISPLAY(vnc));
+			}
+		} else {
+			printf("Unsupported credential type %d\n", g_value_get_enum(cred));
+			vnc_display_close(VNC_DISPLAY(vnc));
+		}
+	}
+
+	g_free(data);
+	if (dialog)
+		gtk_widget_destroy(GTK_WIDGET(dialog));
 }
 
 int main(int argc, char **argv)
diff -r 4c3599147f53 examples/gvncviewer.py
--- a/examples/gvncviewer.py	Mon Jul 30 20:12:10 2007 -0400
+++ b/examples/gvncviewer.py	Mon Jul 30 20:30:44 2007 -0400
@@ -60,36 +60,60 @@ def send_cab(src, vnc):
     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))
+    prompt = 0
+    data = []
 
     for i in range(len(credList)):
-        if credList[i] == gtkvnc.CREDENTIAL_USERNAME:
-            label.append(gtk.Label("Username:"))
+        data.append(None)
+        if credList[i] in (gtkvnc.CREDENTIAL_USERNAME, gtkvnc.CREDENTIAL_PASSWORD):
+            prompt = prompt + 1
+        elif credList[i] == gtkvnc.CREDENTIAL_CLIENTNAME:
+            data[i] = "gvncviewer"
+
+    if prompt:
+        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, prompt)
+
+        row = 0
+        for i in range(len(credList)):
+            if credList[i] == gtkvnc.CREDENTIAL_USERNAME:
+                label.append(gtk.Label("Username:"))
+            elif credList[i] == gtkvnc.CREDENTIAL_PASSWORD:
+                label.append(gtk.Label("Password:"))
+            else:
+                continue
+
+            entry.append(gtk.Entry())
+
+            box.attach(label[row], 0, 1, row, row+1, 0, 0, 3, 3)
+            box.attach(entry[row], 1, 2, row, row+1, 0, 0, 3, 3)
+            row = row + 1
+
+        vbox = dialog.get_child()
+        vbox.add(box)
+
+        dialog.show_all()
+        res = dialog.run()
+        dialog.hide()
+
+        if res == gtk.RESPONSE_OK:
+            row = 0
+            for i in range(len(credList)):
+                if credList[i] in (gtkvnc.CREDENTIAL_USERNAME, gtkvnc.CREDENTIAL_PASSWORD):
+                    data[i] = entry[row].get_text()
+                    row = row + 1
+
+        dialog.destroy()
+
+    for i in range(len(credList)):
+        if i < len(data) and data[i] != None:
+            src.set_credential(credList[i], data[i])
         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()
+            print "Unsupported credential type %d" % (credList[i])
+            src.close()
 
 window = gtk.Window()
 vnc = gtkvnc.Display()
diff -r 4c3599147f53 src/Makefile.am
--- a/src/Makefile.am	Mon Jul 30 20:12:10 2007 -0400
+++ b/src/Makefile.am	Mon Jul 30 20:12:49 2007 -0400
@@ -4,7 +4,8 @@ lib_LTLIBRARIES = libgtk-vnc-1.0.la
 lib_LTLIBRARIES = libgtk-vnc-1.0.la
 
 libgtk_vnc_1_0_la_LIBADD = @GTK_LIBS@ @GNUTLS_LIBS@
-libgtk_vnc_1_0_la_CFLAGS = @GTK_CFLAGS@ @GNUTLS_CFLAGS@ @WARNING_CFLAGS@
+libgtk_vnc_1_0_la_CFLAGS = @GTK_CFLAGS@ @GNUTLS_CFLAGS@ @WARNING_CFLAGS@ \
+                           -DSYSCONFDIR=\""$(sysconfdir)"\"
 libgtk_vnc_1_0_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libgtk-vnc_sym.version \
                             -version-info 0:1:0
 
diff -r 4c3599147f53 src/gvnc.c
--- a/src/gvnc.c	Mon Jul 30 20:12:10 2007 -0400
+++ b/src/gvnc.c	Mon Jul 30 20:35:12 2007 -0400
@@ -33,11 +33,6 @@
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
 
-#define CA_FILE "ca-cert.pem"
-#define CRL_FILE "ca-crl.pem"
-#define KEY_FILE "key.pem"
-#define CERT_FILE "cert.pem"
-
 struct wait_queue
 {
 	gboolean waiting;
@@ -92,6 +87,10 @@ struct gvnc
 	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;
 
 	char read_buffer[4096];
 	size_t read_offset;
@@ -529,36 +528,48 @@ static gnutls_anon_client_credentials gv
 	return anon_cred;
 }
 
-static gnutls_certificate_credentials_t gvnc_tls_initialize_cert_cred(void)
+static gnutls_certificate_credentials_t gvnc_tls_initialize_cert_cred(struct gvnc *vnc)
 {
 	gnutls_certificate_credentials_t x509_cred;
 	int ret;
-	struct stat st;
 
 	if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
 		GVNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
 		return NULL;
 	}
-	if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, CA_FILE, GNUTLS_X509_FMT_PEM)) < 0) {
-		GVNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
+	if (vnc->cred_x509_cacert) {
+		if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
+								  vnc->cred_x509_cacert,
+								  GNUTLS_X509_FMT_PEM)) < 0) {
+			GVNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
+			return NULL;
+		}
+	} else {
+		GVNC_DEBUG("No CA certificate provided\n");
 		return NULL;
 	}
 
-	if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, CERT_FILE, KEY_FILE,
-							 GNUTLS_X509_FMT_PEM)) < 0) {
-		GVNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
-		return NULL;
-	}
-
-	if (stat(CRL_FILE, &st) < 0) {
-		if (errno != ENOENT) {
+	if (vnc->cred_x509_cert && vnc->cred_x509_key) {
+		if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
+								 vnc->cred_x509_cert,
+								 vnc->cred_x509_key,
+								 GNUTLS_X509_FMT_PEM)) < 0) {
+			GVNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
 			return NULL;
 		}
 	} else {
-		if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, CRL_FILE, GNUTLS_X509_FMT_PEM)) < 0) {
+		GVNC_DEBUG("No client cert or key provided\n");
+	}
+
+	if (vnc->cred_x509_cacrl) {
+		if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
+								vnc->cred_x509_cacrl,
+								GNUTLS_X509_FMT_PEM)) < 0) {
 			GVNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
 			return NULL;
 		}
+	} else {
+		GVNC_DEBUG("No CA revocation list provided\n");
 	}
 
 	gnutls_certificate_set_dh_params (x509_cred, dh_params);
@@ -1276,7 +1287,7 @@ static gboolean gvnc_start_tls(struct gv
 				return FALSE;
 			}
 		} else {
-			gnutls_certificate_credentials_t x509_cred = gvnc_tls_initialize_cert_cred();
+			gnutls_certificate_credentials_t x509_cred = gvnc_tls_initialize_cert_cred(gvnc);
 			if (!x509_cred) {
 				gnutls_deinit(gvnc->tls_session);
 				gvnc->has_error = TRUE;
@@ -1354,6 +1365,18 @@ gboolean gvnc_wants_credential_username(
         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;
@@ -1363,6 +1386,16 @@ static gboolean gvnc_has_credentials(gpo
 	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;
 }
@@ -1635,6 +1668,15 @@ void gvnc_close(struct gvnc *gvnc)
 	gvnc->cred_username = NULL;
 	free(gvnc->cred_password);
 	gvnc->cred_password = NULL;
+
+	free(gvnc->cred_x509_cacert);
+	gvnc->cred_x509_cacert = NULL;
+	free(gvnc->cred_x509_cacrl);
+	gvnc->cred_x509_cacrl = NULL;
+	free(gvnc->cred_x509_cert);
+	gvnc->cred_x509_cert = NULL;
+	free(gvnc->cred_x509_key);
+	gvnc->cred_x509_key = NULL;
 
 	gvnc->auth_type = GVNC_AUTH_INVALID;
 	gvnc->auth_subtype = GVNC_AUTH_INVALID;
@@ -1877,6 +1919,53 @@ gboolean gvnc_set_credential_username(st
         return TRUE;
 }
 
+gboolean gvnc_set_credential_x509_cacert(struct gvnc *gvnc, const char *file)
+{
+        GVNC_DEBUG("Set x509 cacert %s\n", file);
+        if (gvnc->cred_x509_cacert)
+                free(gvnc->cred_x509_cacert);
+        if (!(gvnc->cred_x509_cacert = strdup(file))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+gboolean gvnc_set_credential_x509_cacrl(struct gvnc *gvnc, const char *file)
+{
+        GVNC_DEBUG("Set x509 cacrl %s\n", file);
+        if (gvnc->cred_x509_cacrl)
+                free(gvnc->cred_x509_cacrl);
+        if (!(gvnc->cred_x509_cacrl = strdup(file))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+gboolean gvnc_set_credential_x509_key(struct gvnc *gvnc, const char *file)
+{
+        GVNC_DEBUG("Set x509 key %s\n", file);
+        if (gvnc->cred_x509_key)
+                free(gvnc->cred_x509_key);
+        if (!(gvnc->cred_x509_key = strdup(file))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+gboolean gvnc_set_credential_x509_cert(struct gvnc *gvnc, const char *file)
+{
+        GVNC_DEBUG("Set x509 cert %s\n", file);
+        if (gvnc->cred_x509_cert)
+                free(gvnc->cred_x509_cert);
+        if (!(gvnc->cred_x509_cert = strdup(file))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
 
 
 gboolean gvnc_set_local(struct gvnc *gvnc, struct gvnc_framebuffer *fb)
diff -r 4c3599147f53 src/gvnc.h
--- a/src/gvnc.h	Mon Jul 30 20:12:10 2007 -0400
+++ b/src/gvnc.h	Mon Jul 30 20:12:49 2007 -0400
@@ -112,8 +112,14 @@ gboolean gvnc_set_auth_subtype(struct gv
 
 gboolean gvnc_set_credential_password(struct gvnc *gvnc, const char *password);
 gboolean gvnc_set_credential_username(struct gvnc *gvnc, const char *username);
+gboolean gvnc_set_credential_x509_cacert(struct gvnc *gvnc, const char *file);
+gboolean gvnc_set_credential_x509_cacrl(struct gvnc *gvnc, const char *file);
+gboolean gvnc_set_credential_x509_key(struct gvnc *gvnc, const char *file);
+gboolean gvnc_set_credential_x509_cert(struct gvnc *gvnc, const char *file);
+
 gboolean gvnc_wants_credential_password(struct gvnc *gvnc);
 gboolean gvnc_wants_credential_username(struct gvnc *gvnc);
+gboolean gvnc_wants_credential_x509(struct gvnc *gvnc);
 
 gboolean gvnc_initialize(struct gvnc *gvnc, gboolean shared_flag);
 gboolean gvnc_is_initialized(struct gvnc *gvnc);
diff -r 4c3599147f53 src/vncdisplay.c
--- a/src/vncdisplay.c	Mon Jul 30 20:12:10 2007 -0400
+++ b/src/vncdisplay.c	Mon Jul 30 20:52:21 2007 -0400
@@ -19,6 +19,10 @@
 #include <gdk/gdkkeysyms.h>
 #include <sys/ipc.h>
 #include <sys/shm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <pwd.h>
 
 #define VNC_DISPLAY_GET_PRIVATE(obj) \
       (G_TYPE_INSTANCE_GET_PRIVATE((obj), VNC_TYPE_DISPLAY, VncDisplayPrivate))
@@ -485,10 +489,11 @@ static gboolean on_auth_cred(void *opaqu
 {
 	VncDisplay *obj = VNC_DISPLAY(opaque);
 	GValueArray *credList;
-	GValue username, password;
+	GValue username, password, clientname;
 
 	memset(&username, 0, sizeof(username));
 	memset(&password, 0, sizeof(password));
+	memset(&clientname, 0, sizeof(clientname));
 
 	credList = g_value_array_new(2);
 	if (gvnc_wants_credential_username(obj->priv->gvnc)) {
@@ -500,6 +505,11 @@ static gboolean on_auth_cred(void *opaqu
 		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);
+	}
+	if (gvnc_wants_credential_x509(obj->priv->gvnc)) {
+		g_value_init(&clientname, G_PARAM_SPEC_VALUE_TYPE(signalCredParam));
+		g_value_set_enum(&clientname, VNC_DISPLAY_CREDENTIAL_CLIENTNAME);
+		g_value_array_append(credList, &clientname);
 	}
 
 	g_signal_emit (G_OBJECT (obj),
@@ -839,6 +849,61 @@ static void vnc_display_init(GTypeInstan
 	display->priv->gvnc = gvnc_new(&vnc_display_ops, obj);
 }
 
+static int vnc_display_best_path(char *buf,
+				 int buflen,
+				 const char *basedir,
+				 const char *basefile,
+				 char **dirs,
+				 unsigned int ndirs)
+{
+	unsigned int i;
+	for (i = 0 ; i < ndirs ; i++) {
+		struct stat sb;
+		snprintf(buf, buflen-1, "%s/%s/%s", dirs[i], basedir, basefile);
+		buf[buflen-1] = '\0';
+		if (stat(buf, &sb) == 0)
+			return 0;
+	}
+	return -1;
+}
+
+
+static int vnc_display_set_x509_credential(VncDisplay *obj, const char *name)
+{
+	char sysdir[PATH_MAX], userdir[PATH_MAX];
+	struct passwd *pw;
+	char file[PATH_MAX];
+	char *dirs[] = { sysdir, userdir };
+
+	strncpy(sysdir, SYSCONFDIR "/pki", PATH_MAX-1);
+	sysdir[PATH_MAX-1] = '\0';
+
+	if (!(pw = getpwuid(getuid())))
+		return TRUE;
+
+	snprintf(userdir, PATH_MAX-1, "%s/.pki", pw->pw_dir);
+	userdir[PATH_MAX-1] = '\0';
+
+	if (vnc_display_best_path(file, PATH_MAX, "CA", "cacert.pem", dirs, 2) < 0)
+		return TRUE;
+	gvnc_set_credential_x509_cacert(obj->priv->gvnc, file);
+
+	/* Don't mind failures of CRL */
+	if (vnc_display_best_path(file, PATH_MAX, "CA", "cacrl.pem", dirs, 2) == 0)
+		gvnc_set_credential_x509_cacert(obj->priv->gvnc, file);
+
+	/* Set client key & cert if we have them. Server will reject auth
+	 * if it decides it requires them*/
+	if (vnc_display_best_path(file, PATH_MAX, name, "private/clientkey.pem", dirs, 2) == 0)
+		gvnc_set_credential_x509_key(obj->priv->gvnc, file);
+	if (vnc_display_best_path(file, PATH_MAX, name, "clientcert.pem", dirs, 2) == 0)
+		gvnc_set_credential_x509_cert(obj->priv->gvnc, file);
+
+	return FALSE;
+}
+
+
+
 gboolean vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data)
 {
 	switch (type) {
@@ -851,6 +916,9 @@ gboolean vnc_display_set_credential(VncD
 		if (gvnc_set_credential_username(obj->priv->gvnc, data))
 			return FALSE;
 		return TRUE;
+
+	case VNC_DISPLAY_CREDENTIAL_CLIENTNAME:
+		return vnc_display_set_x509_credential(obj, data);
 	}
 
 	return FALSE;
@@ -926,6 +994,7 @@ GType vnc_display_credential_get_type(vo
 		static const GEnumValue values[] = {
 			{ VNC_DISPLAY_CREDENTIAL_PASSWORD, "VNC_DISPLAY_CREDENTIAL_PASSWORD", "password" },
 			{ VNC_DISPLAY_CREDENTIAL_USERNAME, "VNC_DISPLAY_CREDENTIAL_USERNAME", "username" },
+			{ VNC_DISPLAY_CREDENTIAL_CLIENTNAME, "VNC_DISPLAY_CREDENTIAL_CLIENTNAME", "clientname" },
 			{ 0, NULL, NULL }
 		};
 		etype = g_enum_register_static ("VncDisplayCredentialType", values );
diff -r 4c3599147f53 src/vncdisplay.h
--- a/src/vncdisplay.h	Mon Jul 30 20:12:10 2007 -0400
+++ b/src/vncdisplay.h	Mon Jul 30 20:12:49 2007 -0400
@@ -58,6 +58,7 @@ typedef enum
 {
 	VNC_DISPLAY_CREDENTIAL_PASSWORD,
 	VNC_DISPLAY_CREDENTIAL_USERNAME,
+	VNC_DISPLAY_CREDENTIAL_CLIENTNAME,
 } VncDisplayCredential;
 
 G_BEGIN_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]