[seahorse] pkcs11: Implement locking and unlocking of tokens



commit 9993a5fa795e92c9be244d2bfc6baca850702ef6
Author: Stef Walter <stefw collabora co uk>
Date:   Tue Oct 25 13:08:02 2011 +0200

    pkcs11: Implement locking and unlocking of tokens

 libseahorse/seahorse-passphrase.c |    6 +-
 libseahorse/seahorse-passphrase.h |    2 +-
 pgp/seahorse-gpgme-keyring.c      |    2 +-
 pkcs11/Makefile.am                |    1 +
 pkcs11/seahorse-certificate.c     |    2 +-
 pkcs11/seahorse-interaction.c     |  194 ++++++++++++++++++++++++
 pkcs11/seahorse-interaction.h     |   59 ++++++++
 pkcs11/seahorse-pkcs11-actions.c  |  174 +++++++++++++++++++---
 pkcs11/seahorse-pkcs11-actions.h  |    4 +-
 pkcs11/seahorse-token.c           |  295 +++++++++++++++++++++++++++++++++++--
 pkcs11/seahorse-token.h           |   26 ++++
 11 files changed, 728 insertions(+), 37 deletions(-)
---
diff --git a/libseahorse/seahorse-passphrase.c b/libseahorse/seahorse-passphrase.c
index 69fd44f..965ff3b 100644
--- a/libseahorse/seahorse-passphrase.c
+++ b/libseahorse/seahorse-passphrase.c
@@ -178,13 +178,10 @@ seahorse_passphrase_prompt_show (const gchar *title,
 	GtkWidget *chbox;
 	gchar *msg;
 
-	if (!title)
-		title = _("Passphrase");
-
 	if (!prompt)
 		prompt = _("Password:");
 
-	widget = gtk_dialog_new_with_buttons (title, NULL, 0, NULL);
+	widget = gtk_dialog_new_with_buttons (title, NULL, GTK_DIALOG_MODAL, NULL);
 	gtk_window_set_icon_name (GTK_WINDOW (widget), GTK_STOCK_DIALOG_AUTHENTICATION);
 	dialog = GTK_DIALOG (widget);
 
@@ -285,7 +282,6 @@ seahorse_passphrase_prompt_show (const gchar *title,
 
 	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
 	gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
-	gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_NORMAL);
 	gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
 	gtk_widget_show_all (GTK_WIDGET (dialog));
 	gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (dialog)), GDK_CURRENT_TIME);
diff --git a/libseahorse/seahorse-passphrase.h b/libseahorse/seahorse-passphrase.h
index e394a77..34ad050 100644
--- a/libseahorse/seahorse-passphrase.h
+++ b/libseahorse/seahorse-passphrase.h
@@ -32,7 +32,7 @@ GtkDialog*      seahorse_passphrase_prompt_show     (const gchar *title,
                                                      const gchar *prompt,
                                                      const gchar *check,
                                                      gboolean confirm);
-                                                     
+
 const gchar*    seahorse_passphrase_prompt_get      (GtkDialog *dialog);
 
 gboolean        seahorse_passphrase_prompt_checked  (GtkDialog *dialog);
diff --git a/pgp/seahorse-gpgme-keyring.c b/pgp/seahorse-gpgme-keyring.c
index 11b2524..1f5de02 100644
--- a/pgp/seahorse-gpgme-keyring.c
+++ b/pgp/seahorse-gpgme-keyring.c
@@ -103,7 +103,7 @@ passphrase_get (gconstpointer dummy, const gchar *passphrase_hint,
 
 	g_strfreev (split_uid);
 
-	dialog = seahorse_passphrase_prompt_show (NULL, errmsg ? errmsg : label,
+	dialog = seahorse_passphrase_prompt_show (_("Passphrase"), errmsg ? errmsg : label,
 	                                          NULL, NULL, confirm);
 	g_free (label);
 	g_free (errmsg);
diff --git a/pkcs11/Makefile.am b/pkcs11/Makefile.am
index c37f4f9..261fb94 100644
--- a/pkcs11/Makefile.am
+++ b/pkcs11/Makefile.am
@@ -16,6 +16,7 @@ noinst_LTLIBRARIES = libseahorse-pkcs11.la
 
 libseahorse_pkcs11_la_SOURCES = \
 	seahorse-certificate.c seahorse-certificate.h \
+	seahorse-interaction.c seahorse-interaction.h \
 	seahorse-pkcs11-actions.c seahorse-pkcs11-actions.h \
 	seahorse-pkcs11-backend.c seahorse-pkcs11-backend.h \
 	seahorse-pkcs11-certificate-props.c seahorse-pkcs11-certificate-props.h \
diff --git a/pkcs11/seahorse-certificate.c b/pkcs11/seahorse-certificate.c
index f0a7883..664daaa 100644
--- a/pkcs11/seahorse-certificate.c
+++ b/pkcs11/seahorse-certificate.c
@@ -72,7 +72,7 @@ static void
 seahorse_certificate_init (SeahorseCertificate *self)
 {
 	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, SEAHORSE_TYPE_CERTIFICATE, SeahorseCertificatePrivate));
-	self->pv->actions = seahorse_pkcs11_actions_instance ();
+	self->pv->actions = seahorse_pkcs11_object_actions_instance ();
 	gck_attribute_init_invalid (&self->pv->der_value, CKA_VALUE);
 }
 
diff --git a/pkcs11/seahorse-interaction.c b/pkcs11/seahorse-interaction.c
new file mode 100644
index 0000000..be8cb58
--- /dev/null
+++ b/pkcs11/seahorse-interaction.c
@@ -0,0 +1,194 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "seahorse-interaction.h"
+#include "seahorse-passphrase.h"
+
+#include <gnome-keyring-memory.h>
+
+#include <glib/gi18n.h>
+
+enum {
+	PROP_0,
+	PROP_PARENT
+};
+
+struct _SeahorseInteractionPrivate {
+	GtkWindow *parent;
+};
+
+G_DEFINE_TYPE (SeahorseInteraction, seahorse_interaction, G_TYPE_TLS_INTERACTION);
+
+static void
+seahorse_interaction_init (SeahorseInteraction *self)
+{
+	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, SEAHORSE_TYPE_INTERACTION,
+	                                         SeahorseInteractionPrivate));
+}
+
+static void
+seahorse_interaction_set_property (GObject *obj,
+                                   guint prop_id,
+                                   const GValue *value,
+                                   GParamSpec *pspec)
+{
+	SeahorseInteraction *self = SEAHORSE_INTERACTION (obj);
+
+	switch (prop_id) {
+	case PROP_PARENT:
+		seahorse_interaction_set_parent (self, g_value_get_object (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+seahorse_interaction_get_property (GObject *obj,
+                                   guint prop_id,
+                                   GValue *value,
+                                   GParamSpec *pspec)
+{
+	SeahorseInteraction *self = SEAHORSE_INTERACTION (obj);
+
+	switch (prop_id) {
+	case PROP_PARENT:
+		g_value_set_object (value, seahorse_interaction_get_parent (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+seahorse_interaction_dispose (GObject *obj)
+{
+	SeahorseInteraction *self = SEAHORSE_INTERACTION (obj);
+
+	seahorse_interaction_set_parent (self, NULL);
+
+	G_OBJECT_CLASS (seahorse_interaction_parent_class)->dispose (obj);
+}
+
+static gchar *
+calc_description (GTlsPassword *password)
+{
+	const gchar *description = g_tls_password_get_description (password);
+	return g_strdup_printf (_("Enter PIN or password for: %s"), description);
+}
+
+static GTlsInteractionResult
+seahorse_interaction_ask_password (GTlsInteraction *interaction,
+                                   GTlsPassword *password,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+	SeahorseInteraction *self = SEAHORSE_INTERACTION (interaction);
+	GTlsInteractionResult res;
+	GtkDialog *dialog;
+	gchar *description;
+	const gchar *pass;
+	gsize length;
+
+	description = calc_description (password);
+
+	dialog = seahorse_passphrase_prompt_show (NULL, description, NULL, NULL, FALSE);
+
+	g_free (description);
+
+	if (self->pv->parent)
+		gtk_window_set_transient_for (GTK_WINDOW (dialog), self->pv->parent);
+
+	switch (gtk_dialog_run (dialog)) {
+	case GTK_RESPONSE_ACCEPT:
+		pass = seahorse_passphrase_prompt_get (dialog);
+		length = strlen (pass);
+		g_tls_password_set_value_full (password,
+		                               (guchar *)gnome_keyring_memory_strdup (pass),
+		                               length, gnome_keyring_memory_free);
+		res = G_TLS_INTERACTION_HANDLED;
+		break;
+	default:
+		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+		                     "The password request was cancelled by the user");
+		res = G_TLS_INTERACTION_FAILED;
+		break;
+	};
+
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+	return res;
+}
+
+static void
+seahorse_interaction_class_init (SeahorseInteractionClass *klass)
+{
+	GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass);
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->get_property = seahorse_interaction_get_property;
+	object_class->set_property = seahorse_interaction_set_property;
+	object_class->dispose = seahorse_interaction_dispose;
+
+	interaction_class->ask_password = seahorse_interaction_ask_password;
+
+	g_object_class_install_property (object_class, PROP_PARENT,
+	            g_param_spec_object ("parent", "Parent", "Parent window",
+	                                 GTK_TYPE_WINDOW, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	g_type_class_add_private (klass, sizeof (SeahorseInteractionPrivate));
+}
+
+GTlsInteraction *
+seahorse_interaction_new (GtkWindow *parent)
+{
+	return g_object_new (SEAHORSE_TYPE_INTERACTION,
+	                     "parent", parent,
+	                     NULL);
+}
+
+GtkWindow *
+seahorse_interaction_get_parent (SeahorseInteraction *self)
+{
+	g_return_val_if_fail (SEAHORSE_IS_INTERACTION (self), NULL);
+	return self->pv->parent;
+}
+
+void
+seahorse_interaction_set_parent (SeahorseInteraction *self,
+                                 GtkWindow *parent)
+{
+	g_return_if_fail (SEAHORSE_IS_INTERACTION (self));
+	g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
+
+	if (self->pv->parent)
+		g_object_remove_weak_pointer (G_OBJECT (self->pv->parent),
+		                              (gpointer *)&self->pv->parent);
+	self->pv->parent = parent;
+	if (self->pv->parent)
+		g_object_add_weak_pointer (G_OBJECT (self->pv->parent),
+		                           (gpointer *)&self->pv->parent);
+	g_object_notify (G_OBJECT (self), "parent");
+}
diff --git a/pkcs11/seahorse-interaction.h b/pkcs11/seahorse-interaction.h
new file mode 100644
index 0000000..54209ee
--- /dev/null
+++ b/pkcs11/seahorse-interaction.h
@@ -0,0 +1,59 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __SEAHORSE_INTERACTION_H__
+#define __SEAHORSE_INTERACTION_H__
+
+#include <gtk/gtk.h>
+
+#include "seahorse-object.h"
+#include "seahorse-viewer.h"
+
+#define SEAHORSE_TYPE_INTERACTION                  (seahorse_interaction_get_type ())
+#define SEAHORSE_INTERACTION(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_INTERACTION, SeahorseInteraction))
+#define SEAHORSE_INTERACTION_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_INTERACTION, SeahorseInteractionClass))
+#define SEAHORSE_IS_INTERACTION(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_INTERACTION))
+#define SEAHORSE_IS_INTERACTION_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_INTERACTION))
+#define SEAHORSE_INTERACTION_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_INTERACTION, SeahorseInteractionClass))
+
+typedef struct _SeahorseInteraction SeahorseInteraction;
+typedef struct _SeahorseInteractionClass SeahorseInteractionClass;
+typedef struct _SeahorseInteractionPrivate SeahorseInteractionPrivate;
+
+struct _SeahorseInteraction {
+	GTlsInteraction parent_instance;
+	SeahorseInteractionPrivate *pv;
+};
+
+struct _SeahorseInteractionClass {
+	GTlsInteractionClass parent_class;
+};
+
+GType                 seahorse_interaction_get_type                 (void);
+
+GTlsInteraction *     seahorse_interaction_new                      (GtkWindow *parent);
+
+GtkWindow *           seahorse_interaction_get_parent               (SeahorseInteraction *self);
+
+void                  seahorse_interaction_set_parent               (SeahorseInteraction *self,
+                                                                     GtkWindow *parent);
+
+#endif
diff --git a/pkcs11/seahorse-pkcs11-actions.c b/pkcs11/seahorse-pkcs11-actions.c
index 160080f..a5a0bec 100644
--- a/pkcs11/seahorse-pkcs11-actions.c
+++ b/pkcs11/seahorse-pkcs11-actions.c
@@ -25,9 +25,11 @@
 #include "seahorse-pkcs11-actions.h"
 
 #include "seahorse-certificate.h"
+#include "seahorse-interaction.h"
 #include "seahorse-pkcs11.h"
 #include "seahorse-pkcs11-certificate-props.h"
 #include "seahorse-pkcs11-operations.h"
+#include "seahorse-token.h"
 
 #include "seahorse-action.h"
 #include "seahorse-actions.h"
@@ -36,25 +38,161 @@
 #include "seahorse-registry.h"
 #include "seahorse-util.h"
 
-GType   seahorse_pkcs11_actions_get_type           (void) G_GNUC_CONST;
-#define SEAHORSE_TYPE_PKCS11_ACTIONS               (seahorse_pkcs11_actions_get_type ())
-#define SEAHORSE_PKCS11_ACTIONS(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_PKCS11_ACTIONS, SeahorsePkcs11Actions))
-#define SEAHORSE_PKCS11_ACTIONS_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_PKCS11_ACTIONS, SeahorsePkcs11ActionsClass))
-#define SEAHORSE_PKCS11_IS_ACTIONS(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_PKCS11_ACTIONS))
-#define SEAHORSE_PKCS11_IS_ACTIONS_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_PKCS11_ACTIONS))
-#define SEAHORSE_PKCS11_ACTIONS_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_PKCS11_ACTIONS, SeahorsePkcs11ActionsClass))
+GType   seahorse_pkcs11_token_actions_get_type       (void) G_GNUC_CONST;
+#define SEAHORSE_TYPE_PKCS11_TOKEN_ACTIONS           (seahorse_pkcs11_token_actions_get_type ())
+#define SEAHORSE_PKCS11_TOKEN_ACTIONS(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_PKCS11_TOKEN_ACTIONS, SeahorsePkcs11TokenActions))
+#define SEAHORSE_PKCS11_IS_ACTIONS(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_PKCS11_TOKEN_ACTIONS))
 
 typedef struct {
 	SeahorseActions parent;
-} SeahorsePkcs11Actions;
+} SeahorsePkcs11TokenActions;
 
 typedef struct {
 	SeahorseActionsClass parent_class;
-} SeahorsePkcs11ActionsClass;
+} SeahorsePkcs11TokenActionsClass;
+
+G_DEFINE_TYPE (SeahorsePkcs11TokenActions, seahorse_pkcs11_token_actions, SEAHORSE_TYPE_ACTIONS);
+
+static void
+on_token_locked (GObject *source,
+                 GAsyncResult *result,
+                 gpointer user_data)
+{
+	GError *error = NULL;
+
+	seahorse_token_lock_finish (SEAHORSE_TOKEN (source), result, &error);
+	if (error != NULL) {
+		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+			g_warning ("couldn't unlock token: %s", error->message);
+		g_error_free (error);
+	}
+}
+
+static void
+on_token_lock (GtkAction *action,
+               gpointer user_data)
+{
+	GTlsInteraction *interaction;
+
+	interaction = seahorse_interaction_new (seahorse_action_get_window (action));
+	seahorse_token_lock_async (SEAHORSE_TOKEN (user_data), interaction, NULL,
+	                           on_token_locked, NULL);
+	g_object_unref (interaction);
+}
+
+
+static void
+on_token_unlocked (GObject *source,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+	GError *error = NULL;
+
+	seahorse_token_unlock_finish (SEAHORSE_TOKEN (source), result, &error);
+	if (error != NULL) {
+		if (!g_error_matches (error, GCK_ERROR, CKR_FUNCTION_CANCELED))
+			g_warning ("couldn't unlock token: %s", error->message);
+		g_error_free (error);
+	}
+}
+
+static void
+on_token_unlock (GtkAction *action,
+                 gpointer user_data)
+{
+	GTlsInteraction *interaction;
+	GtkWindow *window;
+
+	window = seahorse_action_get_window (action);
+	interaction = seahorse_interaction_new (window);
+
+	seahorse_token_unlock_async (SEAHORSE_TOKEN (user_data), interaction, NULL,
+	                             on_token_unlocked, NULL);
+
+	g_object_unref (interaction);
+}
+
+static const GtkActionEntry TOKEN_ACTIONS[] = {
+	{ "lock", NULL, NULL, NULL,
+	  N_("Lock this token"), G_CALLBACK (on_token_lock) },
+	{ "unlock", NULL, NULL, NULL,
+	  N_("Unlock this token"), G_CALLBACK (on_token_unlock) },
+};
+
+static void
+seahorse_pkcs11_token_actions_init (SeahorsePkcs11TokenActions *self)
+{
+
+}
+
+static GtkActionGroup *
+seahorse_pkcs11_token_actions_clone_for_objects (SeahorseActions *actions,
+                                                 GList *objects)
+{
+	GtkActionGroup *cloned;
+
+	g_return_val_if_fail (objects != NULL, NULL);
+
+	cloned = gtk_action_group_new ("Pkcs11Token");
+
+	if (!objects->next) {
+		gtk_action_group_add_actions_full (cloned, TOKEN_ACTIONS,
+		                                   G_N_ELEMENTS (TOKEN_ACTIONS),
+		                                   g_object_ref (objects->data),
+		                                   g_object_unref);
+
+		g_object_bind_property (objects->data, "lockable",
+		                        gtk_action_group_get_action (cloned, "lock"), "sensitive",
+		                        G_BINDING_SYNC_CREATE);
+		g_object_bind_property (objects->data, "unlockable",
+		                        gtk_action_group_get_action (cloned, "unlock"), "sensitive",
+		                        G_BINDING_SYNC_CREATE);
+	}
+
+	return cloned;
+}
+
+static void
+seahorse_pkcs11_token_actions_class_init (SeahorsePkcs11TokenActionsClass *klass)
+{
+	SeahorseActionsClass *actions_class = SEAHORSE_ACTIONS_CLASS (klass);
+	actions_class->clone_for_objects = seahorse_pkcs11_token_actions_clone_for_objects;
+}
+
+GtkActionGroup *
+seahorse_pkcs11_token_actions_instance (void)
+{
+	static GtkActionGroup *actions = NULL;
+
+	if (actions == NULL) {
+		actions = g_object_new (SEAHORSE_TYPE_PKCS11_TOKEN_ACTIONS,
+		                        "name", "Pkcs11Token",
+		                        NULL);
+		g_object_add_weak_pointer (G_OBJECT (actions),
+		                           (gpointer *)&actions);
+	} else {
+		g_object_ref (actions);
+	}
+
+	return actions;
+}
+
+GType   seahorse_pkcs11_object_actions_get_type       (void) G_GNUC_CONST;
+#define SEAHORSE_TYPE_PKCS11_OBJECT_ACTIONS           (seahorse_pkcs11_object_actions_get_type ())
+#define SEAHORSE_PKCS11_OBJECT_ACTIONS(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_PKCS11_OBJECT_ACTIONS, SeahorsePkcs11ObjectActions))
+#define SEAHORSE_PKCS11_IS_OBJECT_ACTIONS(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_PKCS11_OBJECT_ACTIONS))
+
+typedef struct {
+	SeahorseActions parent;
+} SeahorsePkcs11ObjectActions;
+
+typedef struct {
+	SeahorseActionsClass parent_class;
+} SeahorsePkcs11ObjectActionsClass;
 
 static GQuark QUARK_WINDOW = 0;
 
-G_DEFINE_TYPE (SeahorsePkcs11Actions, seahorse_pkcs11_actions, SEAHORSE_TYPE_ACTIONS);
+G_DEFINE_TYPE (SeahorsePkcs11ObjectActions, seahorse_pkcs11_object_actions, SEAHORSE_TYPE_ACTIONS);
 
 static void
 properties_response (GtkDialog *dialog, gint response_id, gpointer user_data)
@@ -157,20 +295,20 @@ static const GtkActionEntry CERTIFICATES_ACTIONS[] = {
 };
 
 static void
-seahorse_pkcs11_actions_init (SeahorsePkcs11Actions *self)
+seahorse_pkcs11_object_actions_init (SeahorsePkcs11ObjectActions *self)
 {
 
 }
 
 static GtkActionGroup *
-seahorse_pkcs11_actions_clone_for_objects (SeahorseActions *actions,
+seahorse_pkcs11_object_actions_clone_for_objects (SeahorseActions *actions,
                                            GList *objects)
 {
 	GtkActionGroup *cloned;
 
 	g_return_val_if_fail (objects != NULL, NULL);
 
-	cloned = gtk_action_group_new ("Certificate");
+	cloned = gtk_action_group_new ("Pkcs11Object");
 	gtk_action_group_set_translation_domain (cloned, GETTEXT_PACKAGE);
 	gtk_action_group_add_actions_full (cloned, CERTIFICATES_ACTIONS,
 	                                   G_N_ELEMENTS (CERTIFICATES_ACTIONS),
@@ -188,21 +326,21 @@ seahorse_pkcs11_actions_clone_for_objects (SeahorseActions *actions,
 }
 
 static void
-seahorse_pkcs11_actions_class_init (SeahorsePkcs11ActionsClass *klass)
+seahorse_pkcs11_object_actions_class_init (SeahorsePkcs11ObjectActionsClass *klass)
 {
 	SeahorseActionsClass *actions_class = SEAHORSE_ACTIONS_CLASS (klass);
 	QUARK_WINDOW = g_quark_from_static_string ("seahorse-pkcs11-actions-window");
-	actions_class->clone_for_objects = seahorse_pkcs11_actions_clone_for_objects;
+	actions_class->clone_for_objects = seahorse_pkcs11_object_actions_clone_for_objects;
 }
 
 GtkActionGroup *
-seahorse_pkcs11_actions_instance (void)
+seahorse_pkcs11_object_actions_instance (void)
 {
 	static GtkActionGroup *actions = NULL;
 
 	if (actions == NULL) {
-		actions = g_object_new (SEAHORSE_TYPE_PKCS11_ACTIONS,
-		                        "name", "Certificate",
+		actions = g_object_new (SEAHORSE_TYPE_PKCS11_OBJECT_ACTIONS,
+		                        "name", "Pkcs11Object",
 		                        NULL);
 		g_object_add_weak_pointer (G_OBJECT (actions),
 		                           (gpointer *)&actions);
diff --git a/pkcs11/seahorse-pkcs11-actions.h b/pkcs11/seahorse-pkcs11-actions.h
index fd50dc3..9f94e16 100644
--- a/pkcs11/seahorse-pkcs11-actions.h
+++ b/pkcs11/seahorse-pkcs11-actions.h
@@ -24,6 +24,8 @@
 
 #include <gtk/gtk.h>
 
-GtkActionGroup *      seahorse_pkcs11_actions_instance            (void);
+GtkActionGroup *      seahorse_pkcs11_token_actions_instance        (void);
+
+GtkActionGroup *      seahorse_pkcs11_object_actions_instance       (void);
 
 #endif /* __SEAHORSE_PKCS11_ACTIONS_H__ */
diff --git a/pkcs11/seahorse-token.c b/pkcs11/seahorse-token.c
index 9a1f4de..f0e0d46 100644
--- a/pkcs11/seahorse-token.c
+++ b/pkcs11/seahorse-token.c
@@ -30,6 +30,7 @@
 
 #include "seahorse-certificate.h"
 #include "seahorse-pkcs11.h"
+#include "seahorse-pkcs11-actions.h"
 #include "seahorse-pkcs11-helpers.h"
 #include "seahorse-pkcs11-operations.h"
 #include "seahorse-token.h"
@@ -46,13 +47,19 @@ enum {
 	PROP_SLOT,
 	PROP_FLAGS,
 	PROP_URI,
-	PROP_ACTIONS
+	PROP_ACTIONS,
+	PROP_INFO,
+	PROP_LOCKABLE,
+	PROP_UNLOCKABLE
 };
 
 struct _SeahorseTokenPrivate {
 	GckSlot *slot;
 	gchar *uri;
 	GHashTable *objects;
+	GckTokenInfo *info;
+	GckSession *session;
+	GtkActionGroup *actions;
 };
 
 static void          receive_object                      (SeahorseToken *self,
@@ -67,7 +74,6 @@ G_DEFINE_TYPE_EXTENDED (SeahorseToken, seahorse_token, G_TYPE_OBJECT, 0,
                         G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_PLACE, seahorse_token_place_iface);
 );
 
-
 typedef struct {
 	SeahorseToken *token;
 	GCancellable *cancellable;
@@ -139,8 +145,26 @@ on_refresh_next_objects (GObject *source,
 	g_object_unref (res);
 }
 
+static void
+update_token_info (SeahorseToken *self)
+{
+	GckTokenInfo *info;
+	GObject *obj;
+
+	info = gck_slot_get_token_info (self->pv->slot);
+	if (info != NULL) {
+		gck_token_info_free (self->pv->info);
+		self->pv->info = info;
+
+		obj = G_OBJECT (self);
+		g_object_notify (obj, "info");
+		g_object_notify (obj, "lockable");
+		g_object_notify (obj, "unlockable");
+	}
+}
+
 void
-seahorse_token_refresh_async (SeahorseToken *token,
+seahorse_token_refresh_async (SeahorseToken *self,
                               GCancellable *cancellable,
                               GAsyncReadyCallback callback,
                               gpointer user_data)
@@ -152,18 +176,22 @@ seahorse_token_refresh_async (SeahorseToken *token,
 	GList *objects, *l;
 	gulong handle;
 
-	res = g_simple_async_result_new (G_OBJECT (token), callback, user_data,
+	g_return_if_fail (SEAHORSE_IS_TOKEN (self));
+
+	update_token_info (self);
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
 	                                 seahorse_token_refresh_async);
 	closure = g_new0 (pkcs11_refresh_closure, 1);
 	closure->checks = g_hash_table_new_full (seahorse_pkcs11_ulong_hash,
 	                                         seahorse_pkcs11_ulong_equal,
 	                                         g_free, g_object_unref);
-	closure->token = g_object_ref (token);
+	closure->token = g_object_ref (self);
 	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
 	g_simple_async_result_set_op_res_gpointer (res, closure, pkcs11_refresh_free);
 
 	/* Make note of all the objects that were there */
-	objects = gcr_collection_get_objects (GCR_COLLECTION (token));
+	objects = gcr_collection_get_objects (GCR_COLLECTION (self));
 	for (l = objects; l; l = g_list_next (l)) {
 		handle = gck_object_get_handle (l->data);
 		g_hash_table_insert (closure->checks,
@@ -213,6 +241,7 @@ seahorse_token_init (SeahorseToken *self)
 	self->pv->objects = g_hash_table_new_full (seahorse_pkcs11_ulong_hash,
 	                                           seahorse_pkcs11_ulong_equal,
 	                                           g_free, g_object_unref);
+	self->pv->actions = seahorse_pkcs11_token_actions_instance ();
 }
 
 static void
@@ -225,12 +254,13 @@ seahorse_token_constructed (GObject *obj)
 
 	g_return_if_fail (self->pv->slot != NULL);
 
+	seahorse_token_refresh_async (self, NULL, NULL, NULL);
+
 	data = gck_uri_data_new ();
-	data->token_info = gck_slot_get_token_info (self->pv->slot);
+	data->token_info = seahorse_token_get_info (self);
 	self->pv->uri = gck_uri_build (data, GCK_URI_FOR_TOKEN);
+	data->token_info = NULL;
 	gck_uri_data_free (data);
-
-	seahorse_token_refresh_async (self, NULL, NULL, NULL);
 }
 
 static void
@@ -277,7 +307,16 @@ seahorse_token_get_property (GObject *object,
 		g_value_set_string (value, self->pv->uri);
 		break;
 	case PROP_ACTIONS:
-		g_value_set_object (value, NULL);
+		g_value_set_object (value, self->pv->actions);
+		break;
+	case PROP_INFO:
+		g_value_set_boxed (value, self->pv->info);
+		break;
+	case PROP_LOCKABLE:
+		g_value_set_boolean (value, seahorse_token_get_lockable (self));
+		break;
+	case PROP_UNLOCKABLE:
+		g_value_set_boolean (value, seahorse_token_get_unlockable (self));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -300,6 +339,13 @@ seahorse_token_set_property (GObject *object,
 		g_return_if_fail (self->pv->slot);
 		g_object_ref (self->pv->slot);
 		break;
+	case PROP_INFO:
+		g_return_if_fail (!self->pv->info);
+		self->pv->info = g_value_dup_boxed (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
 	};
 }
 
@@ -323,6 +369,7 @@ seahorse_token_finalize (GObject *obj)
 
 	g_hash_table_destroy (self->pv->objects);
 	g_assert (self->pv->slot == NULL);
+	g_clear_object (&self->pv->actions);
 	g_free (self->pv->uri);
 
 	G_OBJECT_CLASS (seahorse_token_parent_class)->finalize (obj);
@@ -354,6 +401,18 @@ seahorse_token_class_init (SeahorseTokenClass *klass)
 	g_object_class_install_property (gobject_class, PROP_FLAGS,
 	         g_param_spec_uint ("flags", "Flags", "Object Token flags.",
 	                            0, G_MAXUINT, 0, G_PARAM_READABLE));
+
+	g_object_class_install_property (gobject_class, PROP_INFO,
+	         g_param_spec_boxed ("info", "Info", "Token info",
+	                             GCK_TYPE_TOKEN_INFO, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (gobject_class, PROP_LOCKABLE,
+	         g_param_spec_boolean ("lockable", "Lockable", "Token can be locked",
+	                               FALSE, G_PARAM_READABLE));
+
+	g_object_class_install_property (gobject_class, PROP_UNLOCKABLE,
+	         g_param_spec_boolean ("unlockable", "Unlockable", "Token can be unlocked",
+	                               FALSE, G_PARAM_READABLE));
 }
 
 static void
@@ -417,6 +476,74 @@ seahorse_token_get_slot (SeahorseToken *self)
 	return self->pv->slot;
 }
 
+GckTokenInfo *
+seahorse_token_get_info (SeahorseToken *self)
+{
+	g_return_val_if_fail (SEAHORSE_IS_TOKEN (self), NULL);
+
+	if (self->pv->info == NULL)
+		update_token_info (self);
+
+	return self->pv->info;
+}
+
+static gboolean
+is_session_logged_in (GckSession *session)
+{
+	GckSessionInfo *info;
+	gboolean logged_in;
+
+	if (session == NULL)
+		return FALSE;
+
+	info = gck_session_get_info (session);
+	logged_in = (info != NULL) &&
+	            (info->state == CKS_RW_USER_FUNCTIONS ||
+	             info->state == CKS_RO_USER_FUNCTIONS ||
+	             info->state == CKS_RW_SO_FUNCTIONS);
+	gck_session_info_free (info);
+
+	return logged_in;
+}
+
+gboolean
+seahorse_token_get_lockable (SeahorseToken *self)
+{
+	GckTokenInfo *info;
+
+	g_return_val_if_fail (SEAHORSE_IS_TOKEN (self), FALSE);
+
+	info = seahorse_token_get_info (self);
+
+	if ((info->flags & CKF_LOGIN_REQUIRED) == 0)
+		return FALSE;
+
+	if ((info->flags & CKF_USER_PIN_INITIALIZED) == 0)
+		return FALSE;
+
+	return is_session_logged_in (self->pv->session);
+
+}
+
+gboolean
+seahorse_token_get_unlockable (SeahorseToken *self)
+{
+	GckTokenInfo *info;
+
+	g_return_val_if_fail (SEAHORSE_IS_TOKEN (self), FALSE);
+
+	info = seahorse_token_get_info (self);
+
+	if ((info->flags & CKF_LOGIN_REQUIRED) == 0)
+		return FALSE;
+
+	if ((info->flags & CKF_USER_PIN_INITIALIZED) == 0)
+		return FALSE;
+
+	return !is_session_logged_in (self->pv->session);
+
+}
+
 static void
 receive_object (SeahorseToken *self,
                 GckObject *obj)
@@ -460,3 +587,151 @@ seahorse_token_remove_object (SeahorseToken *self,
 
 	g_object_unref (object);
 }
+
+static void
+on_session_logout (GObject *source,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	SeahorseToken *self = SEAHORSE_TOKEN (g_async_result_get_source_object (user_data));
+	GError *error = NULL;
+
+	gck_session_logout_finish (GCK_SESSION (source), result, &error);
+	if (error == NULL)
+		seahorse_token_refresh_async (self, NULL, NULL, NULL);
+	else
+		g_simple_async_result_take_error (res, error);
+
+	g_simple_async_result_complete (res);
+	g_object_unref (self);
+	g_object_unref (res);
+}
+
+void
+seahorse_token_lock_async (SeahorseToken *self,
+                           GTlsInteraction *interaction,
+                           GCancellable *cancellable,
+                           GAsyncReadyCallback callback,
+                           gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+
+	g_return_if_fail (SEAHORSE_IS_TOKEN (self));
+	g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction));
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_token_lock_async);
+
+	if (is_session_logged_in (self->pv->session))
+		gck_session_logout_async (self->pv->session, cancellable,
+		                          on_session_logout, g_object_ref (res));
+	else
+		g_simple_async_result_complete_in_idle (res);
+
+	g_object_unref (res);
+}
+
+gboolean
+seahorse_token_lock_finish (SeahorseToken *self,
+                            GAsyncResult *result,
+                            GError **error)
+{
+	g_return_val_if_fail (SEAHORSE_IS_TOKEN (self), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	                      seahorse_token_lock_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
+
+static void
+on_login_interactive (GObject *source,
+                      GAsyncResult *result,
+                      gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	SeahorseToken *self = SEAHORSE_TOKEN (g_async_result_get_source_object (user_data));
+	GError *error = NULL;
+
+	gck_session_logout_finish (GCK_SESSION (source), result, &error);
+	if (error == NULL)
+		seahorse_token_refresh_async (self, NULL, NULL, NULL);
+	else
+		g_simple_async_result_take_error (res, error);
+
+	g_simple_async_result_complete (res);
+	g_object_unref (self);
+	g_object_unref (res);
+}
+
+static void
+on_session_login_open (GObject *source,
+                       GAsyncResult *result,
+                       gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	SeahorseToken *self = SEAHORSE_TOKEN (g_async_result_get_source_object (user_data));
+	GError *error = NULL;
+
+	self->pv->session = gck_session_open_finish (result, &error);
+	if (error == NULL)
+		seahorse_token_refresh_async (self, NULL, NULL, NULL);
+	else
+		g_simple_async_result_take_error (res, error);
+
+	g_simple_async_result_complete (res);
+	g_object_unref (self);
+	g_object_unref (res);
+}
+
+void
+seahorse_token_unlock_async (SeahorseToken *self,
+                             GTlsInteraction *interaction,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+
+	g_return_if_fail (SEAHORSE_IS_TOKEN (self));
+	g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction));
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_token_unlock_async);
+
+	if (is_session_logged_in (self->pv->session)) {
+		g_simple_async_result_complete_in_idle (res);
+
+	} else if (self->pv->session) {
+		gck_session_login_interactive_async (self->pv->session, CKU_USER,
+		                                     interaction, NULL, on_login_interactive,
+		                                     g_object_ref (res));
+	} else {
+		gck_session_open_async (self->pv->slot, GCK_SESSION_LOGIN_USER, interaction,
+		                        NULL, on_session_login_open, g_object_ref (res));
+	}
+
+	g_object_unref (res);
+}
+
+gboolean
+seahorse_token_unlock_finish (SeahorseToken *self,
+                              GAsyncResult *result,
+                              GError **error)
+{
+	g_return_val_if_fail (SEAHORSE_IS_TOKEN (self), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	                      seahorse_token_unlock_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
diff --git a/pkcs11/seahorse-token.h b/pkcs11/seahorse-token.h
index cf2ff55..a33fe56 100644
--- a/pkcs11/seahorse-token.h
+++ b/pkcs11/seahorse-token.h
@@ -49,11 +49,37 @@ GType                  seahorse_token_get_type          (void);
 
 SeahorseToken *        seahorse_token_new               (GckSlot *slot);
 
+GckTokenInfo *         seahorse_token_get_info          (SeahorseToken *self);
+
 GckSlot *              seahorse_token_get_slot          (SeahorseToken *self);
 
+gboolean               seahorse_token_get_lockable      (SeahorseToken *self);
+
+gboolean               seahorse_token_get_unlockable    (SeahorseToken *self);
+
 void                   seahorse_token_remove_object     (SeahorseToken *self,
                                                          GckObject *object);
 
+void                   seahorse_token_lock_async        (SeahorseToken *self,
+                                                         GTlsInteraction *interaction,
+                                                         GCancellable *cancellable,
+                                                         GAsyncReadyCallback callback,
+                                                         gpointer user_data);
+
+gboolean               seahorse_token_lock_finish       (SeahorseToken *self,
+                                                         GAsyncResult *result,
+                                                         GError **error);
+
+void                   seahorse_token_unlock_async      (SeahorseToken *self,
+                                                         GTlsInteraction *interaction,
+                                                         GCancellable *cancellable,
+                                                         GAsyncReadyCallback callback,
+                                                         gpointer user_data);
+
+gboolean               seahorse_token_unlock_finish     (SeahorseToken *self,
+                                                         GAsyncResult *result,
+                                                         GError **error);
+
 void                   seahorse_token_refresh_async     (SeahorseToken *self,
                                                          GCancellable *cancellable,
                                                          GAsyncReadyCallback callback,



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