summaryrefslogtreecommitdiff
path: root/gcr
diff options
context:
space:
mode:
Diffstat (limited to 'gcr')
-rw-r--r--gcr/Makefile.am50
-rw-r--r--gcr/gcr-import-dialog.c452
-rw-r--r--gcr/gcr-import-dialog.glade185
-rw-r--r--gcr/gcr-import-dialog.h86
-rw-r--r--gcr/gcr-importer.c749
-rw-r--r--gcr/gcr-importer.h59
-rw-r--r--gcr/gcr-internal.h8
-rw-r--r--gcr/gcr-library.c (renamed from gcr/gcr-internal.c)105
-rw-r--r--gcr/gcr-parser.c163
-rw-r--r--gcr/gcr-parser.h44
-rw-r--r--gcr/gcr-types.h19
-rw-r--r--gcr/gcr.h46
-rw-r--r--gcr/tests/Makefile.am4
-rw-r--r--gcr/tests/unit-test-parser.c2
14 files changed, 1630 insertions, 342 deletions
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index b1cef7d..0edd1de 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -1,12 +1,24 @@
-incdir = $(includedir)/gcr
+# ------------------------------------------------------------------
+# UI BUILDER
+#
-inc_HEADERS = \
- gcr-parser.h \
- gcr-types.h
+uidir = $(datadir)/gcr/ui/
+
+GLADE_FILES = \
+ gcr-import-dialog.glade
+
+.glade.ui:
+ gtk-builder-convert --skip-windows $< $@
+
+ui_DATA = $(GLADE_FILES:.glade=.ui)
+
+# ------------------------------------------------------------------
+# LIBRARY
INCLUDES = \
-I$(top_builddir) \
-I$(top_srcdir) \
+ $(GTK_CFLAGS) \
$(GOBJECT_CFLAGS) \
$(GLIB_CFLAGS)
@@ -16,17 +28,26 @@ BUILT_SOURCES = \
lib_LTLIBRARIES = libgcr.la
libgcr_la_SOURCES = \
- gcr-internal.c gcr-internal.h \
+ gcr-import-dialog.c gcr-import-dialog.h \
+ gcr-importer.c gcr-importer.h \
+ gcr-internal.h \
+ gcr-library.c \
gcr-parser.c gcr-parser.h \
gcr-types.h \
$(BUILT_SOURCES)
+libgcr_la_CFLAGS = \
+ -DPKCS11_MODULE_PATH=\""$(libdir)/gnome-keyring/gnome-keyring-pkcs11.so"\" \
+ -DGCR_API_SUBJECT_TO_CHANGE \
+ -DUIDIR=\""$(uidir)"\"
+
libgcr_la_LDFLAGS = \
-version-info $(GCR_LT_RELEASE) \
-no-undefined -export-symbols-regex 'gcr_*'
libgcr_la_LIBADD = \
$(top_builddir)/egg/libegg.la \
+ $(top_builddir)/egg/libegg-secure-entry.la \
$(top_builddir)/gp11/libgp11.la \
$(GOBJECT_LIBS) \
$(GLIB_LIBS)
@@ -41,16 +62,24 @@ gcr-marshal.c: gcr-marshal.list $(GLIB_GENMARSHAL)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = gcr-$(GCR_MAJOR).pc
+gcr-$(GCR_MAJOR).pc: gcr.pc
+ cp gcr.pc gcr-$(GCR_MAJOR).pc
+
+# ----------------------------------------------------------------
+
EXTRA_DIST = \
gcr.pc.in \
gcr-marshal.list \
- gcr-import-dialog.glade
+ gcr-import-dialog.glade \
+ $(GLADE_FILES)
-DISTCLEANFILES = \
- gcr-$(GCR_MAJOR).pc
+CLEANFILES = \
+ $(BUILT_SOURCES) \
+ $(ui_DATA) \
+ $(pkgconfig_DATA)
-gcr-$(GCR_MAJOR).pc: gcr.pc
- cp gcr.pc gcr-$(GCR_MAJOR).pc
+DISTCLEANFILES = \
+ $(pkgconfig_DATA)
if WITH_TESTS
TESTS_DIR = tests
@@ -60,4 +89,3 @@ endif
SUBDIRS = . \
$(TESTS_DIR)
-
diff --git a/gcr/gcr-import-dialog.c b/gcr/gcr-import-dialog.c
new file mode 100644
index 0000000..b56b883
--- /dev/null
+++ b/gcr/gcr-import-dialog.c
@@ -0,0 +1,452 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * 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 "gcr-import-dialog.h"
+#include "gcr-internal.h"
+
+#include "egg/egg-secure-entry.h"
+
+enum {
+ PROP_0,
+ PROP_SELECTED_SLOT,
+ PROP_PASSWORD,
+ PROP_PRIMARY_TEXT,
+ PROP_SECONDARY_TEXT
+};
+
+enum {
+ COLUMN_SLOT,
+ COLUMN_ICON,
+ COLUMN_LABEL,
+ N_COLUMNS
+};
+
+struct _GcrImportDialogPrivate {
+ GtkBuilder *builder;
+ EggSecureEntry *entry;
+ GtkComboBox *combo;
+ GtkListStore *slots;
+};
+
+G_DEFINE_TYPE (GcrImportDialog, _gcr_import_dialog, GTK_TYPE_DIALOG);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+populate_slots (GcrImportDialog *self)
+{
+ GList *modules, *m;
+ GList *slots, *s;
+ GtkTreeIter iter;
+ GP11TokenInfo *info;
+ gboolean added;
+
+ g_assert (GCR_IS_IMPORT_DIALOG (self));
+
+ if (self->pv->slots)
+ return;
+
+ self->pv->slots = gtk_list_store_new (N_COLUMNS, GP11_TYPE_SLOT, G_TYPE_STRING, G_TYPE_STRING);
+ gtk_combo_box_set_model (self->pv->combo, GTK_TREE_MODEL (self->pv->slots));
+
+ modules = _gcr_get_pkcs11_modules ();
+ g_return_if_fail (modules);
+
+ gtk_list_store_clear (self->pv->slots);
+
+ added = FALSE;
+ for (m = modules; m; m = g_list_next (m)) {
+
+ g_return_if_fail (GP11_IS_MODULE (m->data));
+ slots = gp11_module_get_slots (m->data, TRUE);
+
+ for (s = slots; s; s = g_list_next (s)) {
+ info = gp11_slot_get_token_info (s->data);
+ if (!(info->flags & CKF_WRITE_PROTECTED)) {
+ gtk_list_store_append (self->pv->slots, &iter);
+ gtk_list_store_set (self->pv->slots, &iter,
+ COLUMN_LABEL, info->label,
+ COLUMN_SLOT, s->data,
+ -1);
+ added = TRUE;
+ }
+ }
+
+ gp11_list_unref_free (slots);
+ }
+
+ if (added)
+ gtk_combo_box_set_active (self->pv->combo, 0);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gcr_import_dialog_real_realize (GtkWidget *base)
+{
+ GcrImportDialog *self = GCR_IMPORT_DIALOG (base);
+ if (GTK_WIDGET_VISIBLE (self->pv->combo))
+ populate_slots (self);
+ GTK_WIDGET_CLASS (_gcr_import_dialog_parent_class)->realize (base);
+}
+
+static GObject*
+gcr_import_dialog_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+ GcrImportDialog *self = GCR_IMPORT_DIALOG (G_OBJECT_CLASS (_gcr_import_dialog_parent_class)->constructor(type, n_props, props));
+ GtkCellRenderer *renderer;
+ GtkWidget *widget;
+
+ g_return_val_if_fail (self, NULL);
+
+ if (!gtk_builder_add_from_file (self->pv->builder, UIDIR "gcr-import-dialog.ui", NULL))
+ g_return_val_if_reached (NULL);
+
+ /* Fill in the dialog from builder */
+ widget = GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "import-dialog"));
+ g_return_val_if_fail (widget, FALSE);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (self)->vbox), widget);
+
+ /* Add a secure entry */
+ self->pv->entry = EGG_SECURE_ENTRY (egg_secure_entry_new ());
+ widget = GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "password-area"));
+ gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (self->pv->entry));
+ gtk_widget_show (GTK_WIDGET (self->pv->entry));
+
+ /* Initialize the combo box */
+ self->pv->combo = GTK_COMBO_BOX (gtk_builder_get_object (self->pv->builder, "slot-combo"));
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->pv->combo), renderer, FALSE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self->pv->combo), renderer, "icon-name", COLUMN_ICON);
+ g_object_set (renderer, "xpad", 3, NULL);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->pv->combo), renderer, TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self->pv->combo), renderer, "text", COLUMN_LABEL);
+
+ /* Add our various buttons */
+ gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_OK, GTK_RESPONSE_OK);
+
+ return G_OBJECT (self);
+}
+
+static void
+_gcr_import_dialog_init (GcrImportDialog *self)
+{
+ self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_IMPORT_DIALOG, GcrImportDialogPrivate);
+ self->pv->builder = gtk_builder_new ();
+}
+
+static void
+gcr_import_dialog_dispose (GObject *obj)
+{
+ G_OBJECT_CLASS (_gcr_import_dialog_parent_class)->dispose (obj);
+}
+
+static void
+gcr_import_dialog_finalize (GObject *obj)
+{
+ GcrImportDialog *self = GCR_IMPORT_DIALOG (obj);
+
+ g_object_unref (self->pv->slots);
+ self->pv->slots = NULL;
+
+ g_object_unref (self->pv->builder);
+ self->pv->builder = NULL;
+
+ G_OBJECT_CLASS (_gcr_import_dialog_parent_class)->finalize (obj);
+}
+
+static void
+gcr_import_dialog_set_property (GObject *obj, guint prop_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ GcrImportDialog *self = GCR_IMPORT_DIALOG (obj);
+
+ switch (prop_id) {
+ case PROP_SELECTED_SLOT:
+ _gcr_import_dialog_set_selected_slot (self, g_value_get_object (value));
+ break;
+ case PROP_PASSWORD:
+ _gcr_import_dialog_set_password (self, g_value_get_pointer (value));
+ break;
+ case PROP_PRIMARY_TEXT:
+ _gcr_import_dialog_set_primary_text (self, g_value_get_string (value));
+ break;
+ case PROP_SECONDARY_TEXT:
+ _gcr_import_dialog_set_secondary_text (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gcr_import_dialog_get_property (GObject *obj, guint prop_id, GValue *value,
+ GParamSpec *pspec)
+{
+ GcrImportDialog *self = GCR_IMPORT_DIALOG (obj);
+
+ switch (prop_id) {
+ case PROP_SELECTED_SLOT:
+ g_value_set_object (value, _gcr_import_dialog_get_selected_slot (self));
+ break;
+ case PROP_PASSWORD:
+ g_value_set_pointer (value, (gpointer)_gcr_import_dialog_get_password (self));
+ break;
+ case PROP_PRIMARY_TEXT:
+ g_value_set_string (value, _gcr_import_dialog_get_primary_text (self));
+ break;
+ case PROP_SECONDARY_TEXT:
+ g_value_set_string (value, _gcr_import_dialog_get_secondary_text (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gcr_import_dialog_class_init (GcrImportDialogClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->constructor = gcr_import_dialog_constructor;
+ gobject_class->dispose = gcr_import_dialog_dispose;
+ gobject_class->finalize = gcr_import_dialog_finalize;
+ gobject_class->set_property = gcr_import_dialog_set_property;
+ gobject_class->get_property = gcr_import_dialog_get_property;
+
+ widget_class->realize = gcr_import_dialog_real_realize;
+
+ g_type_class_add_private (gobject_class, sizeof (GcrImportDialogPrivate));
+
+ g_object_class_install_property (gobject_class, PROP_SELECTED_SLOT,
+ g_param_spec_object ("selected-slot", "Selected Slot", "Selected PKCS#11 slot",
+ GP11_TYPE_SLOT, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_PASSWORD,
+ g_param_spec_pointer ("password", "Password", "Pointer to password",
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_PRIMARY_TEXT,
+ g_param_spec_string ("primary-text", "Primary Text", "Primary dialog text",
+ NULL, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_SECONDARY_TEXT,
+ g_param_spec_string ("secondary-text", "Secondary Text", "Dialog secondary text",
+ NULL, G_PARAM_READWRITE));
+
+ _gcr_initialize ();
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GcrImportDialog*
+_gcr_import_dialog_new (void)
+{
+ GcrImportDialog *dialog = g_object_new (GCR_TYPE_IMPORT_DIALOG, NULL);
+ return g_object_ref_sink (dialog);
+}
+
+gboolean
+_gcr_import_dialog_run (GcrImportDialog *self, GtkWindow *parent)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (GCR_IS_IMPORT_DIALOG (self), FALSE);
+
+ if (parent != NULL)
+ gtk_window_set_transient_for (GTK_WINDOW (self), parent);
+
+ ret = (gtk_dialog_run (GTK_DIALOG (self)) == GTK_RESPONSE_OK);
+
+ if (parent != NULL)
+ gtk_window_set_transient_for (GTK_WINDOW (self), NULL);
+
+ gtk_widget_hide (GTK_WIDGET (self));
+ return ret;
+}
+
+GP11Slot*
+_gcr_import_dialog_get_selected_slot (GcrImportDialog *self)
+{
+ GtkTreeIter iter;
+ GP11Slot *slot;
+
+ g_return_val_if_fail (GCR_IMPORT_DIALOG (self), NULL);
+
+ if (GTK_WIDGET_VISIBLE (self->pv->combo))
+ populate_slots (self);
+ else
+ return NULL;
+
+ if (!gtk_combo_box_get_active_iter (self->pv->combo, &iter))
+ return NULL;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (self->pv->slots), &iter, COLUMN_SLOT, &slot, -1);
+
+ /* We hold the reference to this */
+ if (slot != NULL)
+ g_object_unref (slot);
+
+ return slot;
+}
+
+void
+_gcr_import_dialog_set_selected_slot (GcrImportDialog *self, GP11Slot *slot)
+{
+ GtkTreeIter iter;
+ GP11Slot *it_slot;
+ gboolean matched;
+
+ g_return_if_fail (GCR_IMPORT_DIALOG (self));
+
+ if (GTK_WIDGET_VISIBLE (self->pv->combo))
+ populate_slots (self);
+ else
+ g_return_if_reached ();
+
+ if (slot == NULL) {
+ gtk_combo_box_set_active (self->pv->combo, -1);
+ return;
+ }
+
+ g_return_if_fail (GP11_IS_SLOT (slot));
+
+ matched = FALSE;
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->pv->slots), &iter)) {
+ do {
+ gtk_tree_model_get (GTK_TREE_MODEL (self->pv->slots), &iter, COLUMN_SLOT, &it_slot, -1);
+ if (gp11_slot_equal (it_slot, slot))
+ matched = TRUE;
+ g_object_unref (it_slot);
+ } while (!matched && gtk_tree_model_iter_next (GTK_TREE_MODEL (self->pv->slots), &iter));
+ }
+
+ if (matched) {
+ gtk_combo_box_set_active_iter (self->pv->combo, &iter);
+ } else {
+ gtk_combo_box_set_active (self->pv->combo, -1);
+ g_return_if_reached ();
+ }
+}
+
+void
+_gcr_import_dialog_show_selected_slot (GcrImportDialog *self)
+{
+ g_return_if_fail (GCR_IS_IMPORT_DIALOG (self));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "slot-label")));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "slot-area")));
+}
+
+void
+_gcr_import_dialog_hide_selected_slot (GcrImportDialog *self)
+{
+ g_return_if_fail (GCR_IS_IMPORT_DIALOG (self));
+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "slot-label")));
+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "slot-area")));
+}
+
+const gchar*
+_gcr_import_dialog_get_password (GcrImportDialog *self)
+{
+ g_return_val_if_fail (GCR_IS_IMPORT_DIALOG (self), NULL);
+ return egg_secure_entry_get_text (self->pv->entry);
+}
+
+void
+_gcr_import_dialog_set_password (GcrImportDialog *self, const gchar *password)
+{
+ g_return_if_fail (GCR_IS_IMPORT_DIALOG (self));
+ if (password == NULL)
+ password = "";
+ egg_secure_entry_set_text (self->pv->entry, password);
+}
+
+void
+_gcr_import_dialog_show_password (GcrImportDialog *self)
+{
+ g_return_if_fail (GCR_IS_IMPORT_DIALOG (self));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "password-label")));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "password-area")));
+}
+
+void
+_gcr_import_dialog_hide_password (GcrImportDialog *self)
+{
+ g_return_if_fail (GCR_IS_IMPORT_DIALOG (self));
+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "password-label")));
+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "password-area")));
+}
+
+const gchar*
+_gcr_import_dialog_get_primary_text (GcrImportDialog *self)
+{
+ g_return_val_if_fail (GCR_IS_IMPORT_DIALOG (self), NULL);
+ return gtk_label_get_text (GTK_LABEL (gtk_builder_get_object (self->pv->builder, "primary-text")));
+}
+
+void
+_gcr_import_dialog_set_primary_text (GcrImportDialog *self, const gchar *text)
+{
+ gchar *label;
+
+ g_return_if_fail (GCR_IS_IMPORT_DIALOG (self));
+
+ if (text == NULL)
+ text = "";
+
+ label = g_markup_printf_escaped ("<span size='large' weight='bold'>%s</span>", text);
+ gtk_label_set_markup (GTK_LABEL (gtk_builder_get_object (self->pv->builder, "primary-text")), label);
+ g_free (label);
+
+ g_object_notify (G_OBJECT (self), "primary-text");
+}
+
+const gchar*
+_gcr_import_dialog_get_secondary_text (GcrImportDialog *self)
+{
+ g_return_val_if_fail (GCR_IS_IMPORT_DIALOG (self), NULL);
+ return gtk_label_get_text (GTK_LABEL (gtk_builder_get_object (self->pv->builder, "secondary-text")));
+}
+
+void
+_gcr_import_dialog_set_secondary_text (GcrImportDialog *self, const gchar *text)
+{
+ g_return_if_fail (GCR_IS_IMPORT_DIALOG (self));
+
+ if (text == NULL)
+ text = "";
+
+ gtk_label_set_markup (GTK_LABEL (gtk_builder_get_object (self->pv->builder, "secondary-text")), text);
+ g_object_notify (G_OBJECT (self), "primary-text");
+}
diff --git a/gcr/gcr-import-dialog.glade b/gcr/gcr-import-dialog.glade
index 7da00a1..e91c662 100644
--- a/gcr/gcr-import-dialog.glade
+++ b/gcr/gcr-import-dialog.glade
@@ -1,164 +1,127 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.5 on Sat Jan 17 14:53:28 2009 -->
+<!--Generated with glade3 3.4.5 on Wed Jan 21 16:01:29 2009 -->
<glade-interface>
- <widget class="GtkDialog" id="dialog1">
- <property name="border_width">5</property>
- <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
- <property name="has_separator">False</property>
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox1">
+ <widget class="GtkWindow" id="window1">
+ <child>
+ <widget class="GtkVBox" id="import-dialog">
<property name="visible">True</property>
- <property name="spacing">2</property>
+ <property name="border_width">6</property>
+ <property name="spacing">6</property>
<child>
- <widget class="GtkVBox" id="vbox1">
+ <widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
- <property name="spacing">6</property>
+ <property name="spacing">12</property>
<child>
- <widget class="GtkHBox" id="hbox2">
+ <widget class="GtkImage" id="image1">
<property name="visible">True</property>
- <property name="spacing">12</property>
- <child>
- <widget class="GtkImage" id="image1">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="yalign">1</property>
- <property name="stock">gtk-dialog-authentication</property>
- <property name="icon_size">6</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkVBox" id="vbox2">
- <property name="visible">True</property>
- <property name="spacing">6</property>
- <child>
- <widget class="GtkLabel" id="primary-text">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">&lt;span size='large' weight='bold'&gt;Import Certificates and Keys&lt;/span&gt;</property>
- <property name="use_markup">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkLabel" id="secondary-text">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Secondary prompt text</property>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
+ <property name="xalign">0</property>
+ <property name="yalign">1</property>
+ <property name="stock">gtk-dialog-authentication</property>
+ <property name="icon_size">6</property>
</widget>
<packing>
<property name="expand">False</property>
+ <property name="fill">False</property>
</packing>
</child>
<child>
- <widget class="GtkTable" id="table1">
+ <widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
- <property name="n_rows">2</property>
- <property name="n_columns">2</property>
- <property name="column_spacing">12</property>
- <property name="row_spacing">6</property>
+ <property name="spacing">6</property>
<child>
- <widget class="GtkEntry" id="password-entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- </packing>
- </child>
- <child>
- <widget class="GtkComboBox" id="location-combo">
- <property name="visible">True</property>
- <property name="button_sensitivity">GTK_SENSITIVITY_ON</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label5">
+ <widget class="GtkLabel" id="primary-text">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Password:</property>
+ <property name="label" translatable="yes">&lt;span size='large' weight='bold'&gt;Import Certificates and Keys&lt;/span&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
</widget>
- <packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
</child>
<child>
- <widget class="GtkLabel" id="label4">
+ <widget class="GtkLabel" id="secondary-text">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Import Into:</property>
+ <property name="wrap">True</property>
</widget>
<packing>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
+ <property name="position">1</property>
</packing>
</child>
</widget>
<packing>
- <property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
- <property name="position">1</property>
+ <property name="expand">False</property>
</packing>
</child>
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <child>
+ <widget class="GtkTable" id="table1">
<property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <widget class="GtkAlignment" id="password-area">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkAlignment" id="slot-area">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkComboBox" id="slot-combo">
+ <property name="visible">True</property>
+ <property name="button_sensitivity">GTK_SENSITIVITY_ON</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
<child>
- <widget class="GtkButton" id="button1">
+ <widget class="GtkLabel" id="password-label">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="label" translatable="yes">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="response_id">0</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Password:</property>
</widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
</child>
<child>
- <widget class="GtkButton" id="button2">
+ <widget class="GtkLabel" id="slot-label">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="label" translatable="yes">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="response_id">0</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Import Into:</property>
</widget>
<packing>
- <property name="position">1</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
- <property name="pack_type">GTK_PACK_END</property>
+ <property name="position">1</property>
</packing>
</child>
</widget>
diff --git a/gcr/gcr-import-dialog.h b/gcr/gcr-import-dialog.h
new file mode 100644
index 0000000..2465f22
--- /dev/null
+++ b/gcr/gcr-import-dialog.h
@@ -0,0 +1,86 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * 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 __GCR_IMPORT_DIALOG_H__
+#define __GCR_IMPORT_DIALOG_H__
+
+#include "gcr.h"
+
+#include "gp11/gp11.h"
+
+#include <gtk/gtk.h>
+
+#define GCR_TYPE_IMPORT_DIALOG (_gcr_import_dialog_get_type ())
+#define GCR_IMPORT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_IMPORT_DIALOG, GcrImportDialog))
+#define GCR_IMPORT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_IMPORT_DIALOG, GcrImportDialogClass))
+#define GCR_IS_IMPORT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_IMPORT_DIALOG))
+#define GCR_IS_IMPORT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_IMPORT_DIALOG))
+#define GCR_IMPORT_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_IMPORT_DIALOG, GcrImportDialogClass))
+
+typedef struct _GcrImportDialog GcrImportDialog;
+typedef struct _GcrImportDialogClass GcrImportDialogClass;
+typedef struct _GcrImportDialogPrivate GcrImportDialogPrivate;
+
+struct _GcrImportDialog {
+ GtkDialog parent;
+ GcrImportDialogPrivate *pv;
+};
+
+struct _GcrImportDialogClass {
+ GtkDialogClass parent_class;
+};
+
+GType _gcr_import_dialog_get_type (void);
+
+GcrImportDialog* _gcr_import_dialog_new (void);
+
+gboolean _gcr_import_dialog_run (GcrImportDialog *self,
+ GtkWindow *parent);
+
+GP11Slot* _gcr_import_dialog_get_selected_slot (GcrImportDialog *self);
+
+void _gcr_import_dialog_set_selected_slot (GcrImportDialog *self,
+ GP11Slot *slot);
+
+void _gcr_import_dialog_show_selected_slot (GcrImportDialog *self);
+
+void _gcr_import_dialog_hide_selected_slot (GcrImportDialog *self);
+
+const gchar* _gcr_import_dialog_get_password (GcrImportDialog *self);
+
+void _gcr_import_dialog_set_password (GcrImportDialog *self,
+ const gchar *password);
+
+void _gcr_import_dialog_show_password (GcrImportDialog *self);
+
+void _gcr_import_dialog_hide_password (GcrImportDialog *self);
+
+const gchar* _gcr_import_dialog_get_primary_text (GcrImportDialog *self);
+
+void _gcr_import_dialog_set_primary_text (GcrImportDialog *self,
+ const gchar *text);
+
+const gchar* _gcr_import_dialog_get_secondary_text (GcrImportDialog *self);
+
+void _gcr_import_dialog_set_secondary_text (GcrImportDialog *self,
+ const gchar *text);
+
+#endif /* __GCR_IMPORT_DIALOG_H__ */
diff --git a/gcr/gcr-importer.c b/gcr/gcr-importer.c
index 35abba8..0fe0809 100644
--- a/gcr/gcr-importer.c
+++ b/gcr/gcr-importer.c
@@ -21,46 +21,555 @@
#include "config.h"
+#include "gcr-import-dialog.h"
#include "gcr-importer.h"
+#include "gcr-internal.h"
+#include "gcr-parser.h"
+
+#include <glib/gi18n-lib.h>
enum {
PROP_0,
- PROP_IMPORTER
+ PROP_SLOT,
+ PROP_PARSER,
+ PROP_PROMPT_BEHAVIOR
};
enum {
- SIGNAL,
+ IMPORTED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
-G_DEFINE_TYPE (GcrImporter, gcr_importer, G_TYPE_OBJECT);
+struct _GcrImporterPrivate {
+ GP11Slot *slot;
+ GcrParser *parser;
+ GcrImporterPromptBehavior behavior;
+
+ /* Information about last import */
+ GError *error;
+ gboolean succeeded;
+
+ /* State data during import */
+ gboolean processing;
+ GCancellable *cancel;
+ GInputStream *input;
+ gboolean prompted;
+ gboolean async;
+ GByteArray *buffer;
+ GP11Session *session;
+ GQueue queue;
+
+ /* Extra async stuff */
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+};
+
+/* State forward declarations */
+static void state_cancelled (GcrImporter *self, gboolean async);
+static void state_complete (GcrImporter *self, gboolean async);
+static void state_create_object (GcrImporter *self, gboolean async);
+static void state_open_session (GcrImporter *self, gboolean async);
+static void state_parse_buffer (GcrImporter *self, gboolean async);
+static void state_read_buffer (GcrImporter *self, gboolean async);
+
+static void gcr_importer_async_result (GAsyncResultIface *iface);
+G_DEFINE_TYPE_WITH_CODE (GcrImporter, gcr_importer, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, gcr_importer_async_result));
+
+#define BLOCK 4096
/* -----------------------------------------------------------------------------
* INTERNAL
*/
+static void
+cleanup_state_data (GcrImporter *self)
+{
+ GP11Attributes *attrs;
+
+ if (self->pv->buffer)
+ g_byte_array_free (self->pv->buffer, TRUE);
+ self->pv->buffer = NULL;
+
+ if (self->pv->session)
+ g_object_unref (self->pv->session);
+ self->pv->session = NULL;
+
+ while ((attrs = g_queue_pop_head (&self->pv->queue)) != NULL)
+ gp11_attributes_unref (attrs);
+ g_assert (g_queue_is_empty (&self->pv->queue));
+
+ if (self->pv->input)
+ g_object_unref (self->pv->input);
+ self->pv->input = NULL;
+
+ if (self->pv->cancel)
+ g_object_unref (self->pv->cancel);
+ self->pv->cancel = NULL;
+}
+
+static void
+cleanup_import_data (GcrImporter *self)
+{
+ if (self->pv->error)
+ g_clear_error (&self->pv->error);
+ self->pv->succeeded = TRUE;
+}
+
+static void
+next_state (GcrImporter *self, void (*state) (GcrImporter*, gboolean))
+{
+ g_assert (GCR_IS_IMPORTER (self));
+ g_assert (self->pv->processing);
+ g_assert (state);
+
+ if (self->pv->cancel && g_cancellable_is_cancelled (self->pv->cancel))
+ state = state_cancelled;
+
+ (state) (self, self->pv->async);
+}
+
+/* ---------------------------------------------------------------------------------
+ * COMPLETE
+ */
+
+static void
+state_complete (GcrImporter *self, gboolean async)
+{
+ if (async && self->pv->callback != NULL)
+ (self->pv->callback) (G_OBJECT (self), G_ASYNC_RESULT (self), self->pv->user_data);
+
+ cleanup_state_data (self);
+ self->pv->processing = FALSE;
+}
+
+static void
+state_failure (GcrImporter *self, gboolean async)
+{
+ self->pv->succeeded = FALSE;
+ next_state (self, state_complete);
+}
+
+static void
+state_cancelled (GcrImporter *self, gboolean async)
+{
+ if (self->pv->cancel && g_cancellable_is_cancelled (self->pv->cancel))
+ g_cancellable_cancel (self->pv->cancel);
+ if (self->pv->error)
+ g_error_free (self->pv->error);
+ self->pv->error = g_error_new_literal (GCR_DATA_ERROR, GCR_ERROR_CANCELLED, _("The operation was cancelled"));
+ next_state (self, state_failure);
+}
+
+/* ---------------------------------------------------------------------------------
+ * CREATE OBJECTS
+ */
+
+static void
+complete_create_object (GcrImporter *self, GP11Object *object, GError *error)
+{
+ if (object == NULL) {
+ g_propagate_error (&self->pv->error, error);
+ next_state (self, state_failure);
+
+ } else {
+ g_signal_emit (self, signals[IMPORTED], 0, object);
+ g_object_unref (object);
+ next_state (self, state_create_object);
+ }
+}
+
+static void
+on_create_object (GObject *obj, GAsyncResult *res, gpointer user_data)
+{
+ GError *error = NULL;
+ GP11Object *object = gp11_session_create_object_finish (GP11_SESSION (obj), res, &error);
+ complete_create_object (GCR_IMPORTER (user_data), object, error);
+}
+
+static void
+state_create_object (GcrImporter *self, gboolean async)
+{
+ GP11Attributes *attrs;
+ GP11Object *object;
+ GError *error = NULL;
+
+ /* No more objects */
+ if (g_queue_is_empty (&self->pv->queue)) {
+ next_state (self, state_complete);
+
+ } else {
+
+ /* Pop first one off the list */
+ attrs = g_queue_pop_head (&self->pv->queue);
+ g_assert (attrs);
+
+ gp11_attributes_add_ulong (attrs, CKA_TOKEN, CK_TRUE);
+
+ if (async) {
+ gp11_session_create_object_async (self->pv->session, attrs, self->pv->cancel,
+ on_create_object, self);
+ } else {
+ object = gp11_session_create_object_full (self->pv->session, attrs, self->pv->cancel, &error);
+ complete_create_object (self, object, error);
+ }
+
+ gp11_attributes_unref (attrs);
+ }
+}
+
+/* ---------------------------------------------------------------------------------
+ * OPEN SESSION
+ */
+
+static void
+complete_open_session (GcrImporter *self, GP11Session *session, GError *error)
+{
+ if (!session) {
+ g_propagate_error (&self->pv->error, error);
+ next_state (self, state_failure);
+ } else {
+ self->pv->session = session;
+ next_state (self, state_create_object);
+ }
+}
+
+static void
+on_open_session (GObject *obj, GAsyncResult *res, gpointer user_data)
+{
+ GError *error = NULL;
+ GP11Session *session = gp11_slot_open_session_finish (GP11_SLOT (obj), res, &error);
+ complete_open_session (GCR_IMPORTER (user_data), session, error);
+}
+
+static void
+state_open_session (GcrImporter *self, gboolean async)
+{
+ GP11Session *session;
+ GError *error = NULL;
+
+ if (!self->pv->slot) {
+ g_set_error (&self->pv->error, GCR_DATA_ERROR, GCR_ERROR_FAILURE, _("No location available to import to"));
+ next_state (self, state_failure);
+
+ } else {
+
+ if (async) {
+ gp11_slot_open_session_async (self->pv->slot, CKF_RW_SESSION,
+ self->pv->cancel, on_open_session, self);
+ } else {
+ session = gp11_slot_open_session_full (self->pv->slot, CKF_RW_SESSION,
+ self->pv->cancel, &error);
+ complete_open_session (self, session, error);
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------------------
+ * IMPORT PROMPT
+ */
+
+static void
+complete_import_prompt (GcrImporter *self, GcrImportDialog *dialog, gint response)
+{
+ GP11Slot *slot;
+
+ gtk_widget_hide (GTK_WIDGET (dialog));
+ self->pv->prompted = TRUE;
+
+ /* No dialog or dialog completed */
+ if (response == GTK_RESPONSE_OK) {
+
+ slot = _gcr_import_dialog_get_selected_slot (dialog);
+ gcr_importer_set_slot (self, slot);
+ next_state (self, state_open_session);
+
+ /* The dialog was cancelled or closed */
+ } else {
+ next_state (self, state_cancelled);
+ }
+}
+
+static void
+on_prompt_response (GtkDialog *dialog, gint response, gpointer user_data)
+{
+ complete_import_prompt (GCR_IMPORTER (user_data), GCR_IMPORT_DIALOG (dialog), response);
+ g_object_unref (dialog);
+}
+
+static void
+state_import_prompt (GcrImporter *self, gboolean async)
+{
+ GcrImportDialog *dialog;
+ gboolean prompt;
+ gint response;
+
+ g_assert (GCR_IS_IMPORTER (self));
+
+ /* No need to prompt */
+ if (self->pv->prompted == TRUE)
+ prompt = FALSE;
+ else if (self->pv->behavior == GCR_IMPORTER_PROMPT_ALWAYS)
+ prompt = TRUE;
+ else if (self->pv->behavior == GCR_IMPORTER_PROMPT_NEVER)
+ prompt = FALSE;
+ else
+ prompt = self->pv->slot ? FALSE : TRUE;
+
+ if (prompt == FALSE) {
+ next_state (self, state_open_session);
+
+ } else {
+
+ dialog = _gcr_import_dialog_new ();
+
+ _gcr_import_dialog_set_primary_text (dialog, _("Import Certificates/Keys"));
+ _gcr_import_dialog_hide_password (dialog);
+
+ if (self->pv->slot) {
+ _gcr_import_dialog_set_selected_slot (dialog, self->pv->slot);
+ _gcr_import_dialog_hide_selected_slot (dialog);
+ } else {
+ _gcr_import_dialog_set_secondary_text (dialog, _("Choose a location to store the imported certificates/keys."));
+ }
+
+ /* Prompt without blocking main loop */
+ if (async) {
+ g_signal_connect (dialog, "response", G_CALLBACK (on_prompt_response), self);
+ gtk_widget_show (GTK_WIDGET (dialog));
+
+ /* Block mainloop */
+ } else {
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ complete_import_prompt (self, dialog, response);
+ g_object_unref (dialog);
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------------------
+ * PARSING
+ */
+
+static const gchar*
+prepare_auth_primary (CK_OBJECT_CLASS klass)
+{
+ if (klass == CKO_PRIVATE_KEY)
+ return _("Enter password to unlock the private key");
+ else if (klass == CKO_CERTIFICATE)
+ return _("Enter password to unlock the certificate");
+ else
+ return _("Enter password to unlock");
+}
+
+static gchar*
+prepare_auth_secondary (CK_OBJECT_CLASS klass, const gchar *label)
+{
+ if (label == NULL) {
+ if (klass == CKO_PRIVATE_KEY)
+ return g_strdup (_("In order to import the private key, it must be unlocked"));
+ else if (klass == CKO_CERTIFICATE)
+ return g_strdup (_("In order to import the certificate, it must be unlocked"));
+ else
+ return g_strdup (_("In order to import the data, it must be unlocked"));
+ } else {
+ if (klass == CKO_PRIVATE_KEY)
+ return g_strdup_printf (_("In order to import the private key '%s', it must be unlocked"), label);
+ else if (klass == CKO_CERTIFICATE)
+ return g_strdup_printf (_("In order to import the certificate '%s', it must be unlocked"), label);
+ else
+ return g_strdup_printf (_("In order to import '%s', it must be unlocked"), label);
+ }
+}
+
+static void
+on_parser_parsed (GcrParser *parser, GcrImporter *self)
+{
+ GP11Attributes *attrs;
+
+ g_return_if_fail (GCR_IS_PARSER (parser));
+ g_return_if_fail (GCR_IS_IMPORTER (self));
+
+ attrs = gcr_parser_get_parsed_attributes (parser);
+ g_return_if_fail (attrs);
+ g_queue_push_tail (&self->pv->queue, gp11_attributes_ref (attrs));
+}
+
+static gboolean
+on_parser_authenticate (GcrParser *parser, gint count, GcrImporter *self)
+{
+ GcrImportDialog *dialog;
+ GP11Attributes *attrs;
+ const gchar *password;
+ gchar *text, *label;
+ GP11Slot *slot;
+ gulong klass;
+
+ dialog = _gcr_import_dialog_new ();
+
+ if (self->pv->slot)
+ _gcr_import_dialog_set_selected_slot (dialog, self->pv->slot);
+
+ /* Figure out the text for the dialog */
+ attrs = gcr_parser_get_parsed_attributes (parser);
+ g_return_val_if_fail (attrs, FALSE);
+
+ if (!gp11_attributes_find_ulong (attrs, CKA_CLASS, &klass))
+ klass = (gulong)-1;
+ if (!gp11_attributes_find_string (attrs, CKA_LABEL, &label))
+ label = NULL;
+
+ text = prepare_auth_secondary (klass, label);
+ _gcr_import_dialog_set_primary_text (dialog, prepare_auth_primary (klass));
+ _gcr_import_dialog_set_secondary_text (dialog, text);
+ g_free (label);
+ g_free (text);
+
+ if (!_gcr_import_dialog_run (dialog, NULL))
+ return FALSE;
+
+ slot = _gcr_import_dialog_get_selected_slot (dialog);
+ gcr_importer_set_slot (self, slot);
+
+ password = _gcr_import_dialog_get_password (dialog);
+ gcr_parser_add_password (parser, password);
+
+ g_object_unref (dialog);
+ self->pv->prompted = TRUE;
+ return TRUE;
+}
+
+static void
+state_parse_buffer (GcrImporter *self, gboolean async)
+{
+ GError *error = NULL;
+ GcrParser *parser;
+ gulong parsed_conn;
+ gulong auth_conn;
+ gboolean ret;
+
+ g_assert (GCR_IS_IMPORTER (self));
+ g_assert (self->pv->buffer);
+
+ parser = gcr_importer_get_parser (self);
+ g_object_ref (parser);
+
+ /* Listen in to the parser */
+ parsed_conn = g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), self);
+ auth_conn = g_signal_connect (parser, "authenticate", G_CALLBACK (on_parser_authenticate), self);
+
+ ret = gcr_parser_parse_data (parser, self->pv->buffer->data, self->pv->buffer->len, &error);
+
+ /* An optimization to free data early as possible */
+ g_byte_array_free (self->pv->buffer, TRUE);
+ self->pv->buffer = NULL;
+
+ g_signal_handler_disconnect (parser, parsed_conn);
+ g_signal_handler_disconnect (parser, auth_conn);
+ g_object_unref (parser);
+
+ if (ret == TRUE) {
+ next_state (self, state_import_prompt);
+ } else {
+ g_propagate_error (&self->pv->error, error);
+ next_state (self, state_failure);
+ }
+}
+
+/* ---------------------------------------------------------------------------------
+ * BUFFER READING
+ */
+
+static void
+complete_read_buffer (GcrImporter *self, gssize count, GError *error)
+{
+ g_assert (GCR_IS_IMPORTER (self));
+ g_assert (self->pv->buffer);
+
+ /* A failure */
+ if (count == -1) {
+ g_propagate_error (&self->pv->error, error);
+ next_state (self, state_failure);
+ } else {
+
+ g_return_if_fail (count >= 0 && count <= BLOCK);
+ g_byte_array_set_size (self->pv->buffer, self->pv->buffer->len - (BLOCK - count));
+
+ /* Finished reading */
+ if (count == 0) {
+
+ /* Optimization, unref input early */
+ g_object_unref (self->pv->input);
+ self->pv->input = NULL;
+
+ next_state (self, state_parse_buffer);
+
+ /* Read the next block */
+ } else {
+ next_state (self, state_read_buffer);
+ }
+ }
+
+}
+
+static void
+on_read_buffer (GObject *obj, GAsyncResult *res, gpointer user_data)
+{
+ GError *error = NULL;
+ gssize count;
+
+ count = g_input_stream_read_finish (G_INPUT_STREAM (obj), res, &error);
+ complete_read_buffer (user_data, count, error);
+}
+
+static void
+state_read_buffer (GcrImporter *self, gboolean async)
+{
+ GError *error = NULL;
+ gssize count;
+ gsize at;
+
+ g_assert (GCR_IS_IMPORTER (self));
+ g_assert (G_IS_INPUT_STREAM (self->pv->input));
+
+ if (!self->pv->buffer)
+ self->pv->buffer = g_byte_array_sized_new (BLOCK);
+
+ at = self->pv->buffer->len;
+ g_byte_array_set_size (self->pv->buffer, at + BLOCK);
+
+ if (async) {
+ g_input_stream_read_async (self->pv->input, self->pv->buffer->data + at,
+ BLOCK, G_PRIORITY_DEFAULT, self->pv->cancel,
+ on_read_buffer, self);
+ } else {
+ count = g_input_stream_read (self->pv->input, self->pv->buffer->data + at,
+ BLOCK, self->pv->cancel, &error);
+ complete_read_buffer (self, count, error);
+ }
+}
+
/* -----------------------------------------------------------------------------
* OBJECT
*/
-
static GObject*
gcr_importer_constructor (GType type, guint n_props, GObjectConstructParam *props)
{
GcrImporter *self = GCR_IMPORTER (G_OBJECT_CLASS (gcr_importer_parent_class)->constructor(type, n_props, props));
g_return_val_if_fail (self, NULL);
-
-
return G_OBJECT (self);
}
static void
gcr_importer_init (GcrImporter *self)
{
-
+ self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_IMPORTER, GcrImporterPrivate);
+ self->pv->behavior = GCR_IMPORTER_PROMPT_NEEDED;
+ g_queue_init (&self->pv->queue);
}
static void
@@ -68,6 +577,17 @@ gcr_importer_dispose (GObject *obj)
{
GcrImporter *self = GCR_IMPORTER (obj);
+ cleanup_state_data (self);
+ cleanup_import_data (self);
+
+ if (self->pv->parser)
+ g_object_unref (self->pv->parser);
+ self->pv->parser = NULL;
+
+ if (self->pv->slot)
+ g_object_unref (self->pv->slot);
+ self->pv->slot = NULL;
+
G_OBJECT_CLASS (gcr_importer_parent_class)->dispose (obj);
}
@@ -76,6 +596,9 @@ gcr_importer_finalize (GObject *obj)
{
GcrImporter *self = GCR_IMPORTER (obj);
+ g_assert (!self->pv->parser);
+ g_assert (!self->pv->slot);
+
G_OBJECT_CLASS (gcr_importer_parent_class)->finalize (obj);
}
@@ -86,7 +609,14 @@ gcr_importer_set_property (GObject *obj, guint prop_id, const GValue *value,
GcrImporter *self = GCR_IMPORTER (obj);
switch (prop_id) {
- case PROP_IMPORTER:
+ case PROP_PARSER:
+ gcr_importer_set_parser (self, g_value_get_object (value));
+ break;
+ case PROP_SLOT:
+ gcr_importer_set_slot (self, g_value_get_object (value));
+ break;
+ case PROP_PROMPT_BEHAVIOR:
+ gcr_importer_set_prompt_behavior (self, (GcrImporterPromptBehavior)g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -101,7 +631,14 @@ gcr_importer_get_property (GObject *obj, guint prop_id, GValue *value,
GcrImporter *self = GCR_IMPORTER (obj);
switch (prop_id) {
- case PROP_IMPORTER:
+ case PROP_PARSER:
+ g_value_set_object (value, gcr_importer_get_parser (self));
+ break;
+ case PROP_SLOT:
+ g_value_set_object (value, gcr_importer_get_slot (self));
+ break;
+ case PROP_PROMPT_BEHAVIOR:
+ g_value_set_int (value, gcr_importer_get_prompt_behavior (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -120,17 +657,49 @@ gcr_importer_class_init (GcrImporterClass *klass)
gobject_class->set_property = gcr_importer_set_property;
gobject_class->get_property = gcr_importer_get_property;
- g_object_class_install_property (gobject_class, PROP_IMPORTER,
- g_param_spec_pointer ("importer", "Importer", "Importer.", G_PARAM_READWRITE));
+ g_type_class_add_private (gobject_class, sizeof (GcrImporterPrivate));
+
+ g_object_class_install_property (gobject_class, PROP_PARSER,
+ g_param_spec_object ("parser", "Parser", "Parser used to parse imported data",
+ GCR_TYPE_PARSER, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_PARSER,
+ g_param_spec_object ("slot", "Slot", "PKCS#11 slot to import data into",
+ GP11_TYPE_SLOT, G_PARAM_READWRITE));
- signals[SIGNAL] = g_signal_new ("signal", GCR_TYPE_IMPORTER,
- G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcrImporterClass, signal),
+ g_object_class_install_property (gobject_class, PROP_PROMPT_BEHAVIOR,
+ g_param_spec_int ("prompt-behavior", "Prompt Behavior", "Import Prompt Behavior",
+ 0, G_MAXINT, GCR_IMPORTER_PROMPT_NEEDED, G_PARAM_READWRITE));
+
+ signals[IMPORTED] = g_signal_new ("imported", GCR_TYPE_IMPORTER,
+ G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcrImporterClass, imported),
NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 0);
+ G_TYPE_NONE, 1, GP11_TYPE_OBJECT);
_gcr_initialize ();
}
+static gpointer
+gcr_importer_real_get_user_data (GAsyncResult *base)
+{
+ g_return_val_if_fail (GCR_IS_IMPORTER (base), NULL);
+ return GCR_IMPORTER (base)->pv->user_data;
+}
+
+static GObject*
+gcr_importer_real_get_source_object (GAsyncResult *base)
+{
+ g_return_val_if_fail (GCR_IS_IMPORTER (base), NULL);
+ return G_OBJECT (base);
+}
+
+static void
+gcr_importer_async_result (GAsyncResultIface *iface)
+{
+ iface->get_source_object = gcr_importer_real_get_source_object;
+ iface->get_user_data = gcr_importer_real_get_user_data;
+}
+
/* -----------------------------------------------------------------------------
* PUBLIC
*/
@@ -141,73 +710,133 @@ gcr_importer_new (void)
return g_object_new (GCR_TYPE_IMPORTER, NULL);
}
-gboolean
-gcr_importer_import_data (GcrImporter *self, const guchar *data, gsize n_data,
- GError *err)
+GcrParser*
+gcr_importer_get_parser (GcrImporter *self)
{
- GckParser *parser;
- gulong parsed_conn;
- gulong auth_conn;
- gboolean ret;
-
- g_return_val_if_fail (GCR_IS_IMPORTER (self), FALSE);
- g_return_val_if_fail (data || !n_data, FALSE);
- g_return_val_if_fail (!error || !*error, FALSE);
+ g_return_val_if_fail (GCR_IS_IMPORTER (self), NULL);
+ if (!self->pv->parser)
+ self->pv->parser = gcr_parser_new ();
+ return self->pv->parser;
+}
+void
+gcr_importer_set_parser (GcrImporter *self, GcrParser *parser)
+{
+ g_return_if_fail (GCR_IS_IMPORTER (self));
+
+ if (parser)
+ g_object_ref (parser);
+ if (self->pv->parser)
+ g_object_unref (self->pv->parser);
+ self->pv->parser = parser;
+ g_object_notify (G_OBJECT (self), "parser");
+}
- xxxx;
+GP11Slot*
+gcr_importer_get_slot (GcrImporter *self)
+{
+ g_return_val_if_fail (GCR_IS_IMPORTER (self), NULL);
+ return self->pv->slot;
+}
+void
+gcr_importer_set_slot (GcrImporter *self, GP11Slot *slot)
+{
+ g_return_if_fail (GCR_IS_IMPORTER (self));
+
+ if (slot)
+ g_object_ref (slot);
+ if (self->pv->slot)
+ g_object_unref (self->pv->slot);
+ self->pv->slot = slot;
+ g_object_notify (G_OBJECT (self), "slot");
+}
- /*
- * Parse to see if it's something that needs a password
- * if we can't prompt,
- * return an error
- * Possibly prompt, if password needed, with all information necessary
- *
- */
+GcrImporterPromptBehavior
+gcr_importer_get_prompt_behavior (GcrImporter *self)
+{
+ g_return_val_if_fail (GCR_IS_IMPORTER (self), GCR_IMPORTER_PROMPT_NEEDED);
+ return self->pv->behavior;
+}
+void
+gcr_importer_set_prompt_behavior (GcrImporter *self, GcrImporterPromptBehavior behavior)
+{
+ g_return_if_fail (GCR_IMPORTER (self));
+ self->pv->behavior = behavior;
+ g_object_notify (G_OBJECT (self), "prompt-behavior");
+}
- g_object_ref (self);
+gboolean
+gcr_importer_import (GcrImporter *self, GInputStream *input,
+ GCancellable *cancel, GError **error)
+{
+ g_return_val_if_fail (GCR_IS_IMPORTER (self), FALSE);
+ g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+ g_return_val_if_fail (!self->pv->processing, FALSE);
- parser = gcr_importer_get_parser (self);
+ cleanup_import_data (self);
- /* Listen in to the parser */
- g_object_ref (parser);
- parsed_conn = g_signal_connect (parser, "parsed-item", G_CALLBACK (parser_parsed_item), self);
- auth_conn = g_signal_connect (parser, "authenticate", G_CALLBACK (parser_authenticate), self);
+ self->pv->input = g_object_ref (input);
+ if (cancel)
+ self->pv->cancel = g_object_ref (cancel);
+ self->pv->processing = TRUE;
+ self->pv->async = FALSE;
- /* Feed the parser the data */
- ret = gcr_parser_parse_data (parser, data, n_data, err);
+ next_state (self, state_read_buffer);
- /* Now we should have all the data ready, check if we should prompt... */
- /* Import data one by one into module */
+ g_assert (!self->pv->processing);
+ g_assert (!self->pv->input);
+ g_assert (!self->pv->cancel);
- g_signal_handler_disconnect (parser, parsed_conn);
- g_signal_handler_disconnect (parser, auth_conn);
- g_object_unref (parser);
+ if (!self->pv->succeeded) {
+ g_propagate_error (error, self->pv->error);
+ self->pv->error = NULL;
+ return FALSE;
+ }
- g_object_unref (self);
+ return TRUE;
+}
- return ret;
+void
+gcr_importer_import_async (GcrImporter *self, GInputStream *input, GCancellable *cancel,
+ GAsyncReadyCallback callback, gpointer user_data)
+{
+ g_return_if_fail (GCR_IS_IMPORTER (self));
+ g_return_if_fail (G_IS_INPUT_STREAM (input));
+ g_return_if_fail (!self->pv->processing);
+
+ cleanup_import_data (self);
+
+ self->pv->input = g_object_ref (input);
+ if (cancel)
+ self->pv->cancel = g_object_ref (cancel);
+ self->pv->processing = TRUE;
+ self->pv->async = TRUE;
+ self->pv->callback = callback;
+ self->pv->user_data = user_data;
+
+ next_state (self, state_read_buffer);
+ g_assert (self->pv->processing);
}
gboolean
-gcr_importer_import_file (GcrImporter *self, const gchar *filename,
- GError *err)
+gcr_importer_import_finish (GcrImporter *self, GAsyncResult *res, GError **error)
{
- gboolean ret;
- gchar *data;
- gsize n_data;
-
g_return_val_if_fail (GCR_IS_IMPORTER (self), FALSE);
- g_return_val_if_fail (filename, FALSE);
+ g_return_val_if_fail (GCR_IMPORTER (res) == self, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
+ g_return_val_if_fail (!self->pv->processing, FALSE);
- if (!g_file_get_contents (filename, &data, &n_data, err))
- return FALSE;
+ g_assert (!self->pv->input);
+ g_assert (!self->pv->cancel);
- ret = gcr_importer_import_data (self, (const guchar*)data, n_data, error);
- g_free (data);
+ if (!self->pv->succeeded) {
+ g_propagate_error (error, self->pv->error);
+ self->pv->error = NULL;
+ return FALSE;
+ }
- return ret;
+ return TRUE;
}
diff --git a/gcr/gcr-importer.h b/gcr/gcr-importer.h
index dac1d51..ed366f3 100644
--- a/gcr/gcr-importer.h
+++ b/gcr/gcr-importer.h
@@ -22,8 +22,17 @@
#ifndef __GCR_IMPORTER_H__
#define __GCR_IMPORTER_H__
+#include "gcr.h"
+#include "gcr-parser.h"
+
#include <glib-object.h>
+typedef enum {
+ GCR_IMPORTER_PROMPT_NEEDED,
+ GCR_IMPORTER_PROMPT_ALWAYS,
+ GCR_IMPORTER_PROMPT_NEVER
+} GcrImporterPromptBehavior;
+
#define GCR_TYPE_IMPORTER (gcr_importer_get_type ())
#define GCR_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_IMPORTER, GcrImporter))
#define GCR_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_IMPORTER, GcrImporterClass))
@@ -33,49 +42,53 @@
typedef struct _GcrImporter GcrImporter;
typedef struct _GcrImporterClass GcrImporterClass;
+typedef struct _GcrImporterPrivate GcrImporterPrivate;
struct _GcrImporter {
GObject parent;
+ GcrImporterPrivate *pv;
};
struct _GcrImporterClass {
GObjectClass parent_class;
- /* signals --------------------------------------------------------- */
+ /* signals */
- void (*signal) (GcrImporter *self, GkrImportedItem *item);
+ void (*imported) (GcrImporter *self, GP11Object *object);
};
-GType gcr_importer_get_type (void);
+GType gcr_importer_get_type (void);
-GcrImporter* gcr_importer_new (void);
+GcrImporter* gcr_importer_new (void);
-GcrImporter* gcr_importer_new_for_module (GP11Module *module);
+GcrParser* gcr_importer_get_parser (GcrImporter *self);
-GcrImporter* gcr_importer_new_for_module_funcs (gpointer pkcs11_funcs);
+void gcr_importer_set_parser (GcrImporter *self,
+ GcrParser *parser);
-void gcr_importer_set_slot (GcrImporter *self,
- GP11Slot *slot);
+struct _GP11Slot* gcr_importer_get_slot (GcrImporter *self);
-void gcr_importer_set_slot_id (GcrImporter *self,
- gulong slot_id);
+void gcr_importer_set_slot (GcrImporter *self,
+ struct _GP11Slot *slot);
-void gcr_importer_set_parser (GcrImporter *self,
- GcrParser *parser);
+GcrImporterPromptBehavior gcr_importer_get_prompt_behavior (GcrImporter *self);
-void gcr_importer_set_window (GcrImporter *self,
- GtkWindow *window);
+void gcr_importer_set_prompt_behavior (GcrImporter *self,
+ GcrImporterPromptBehavior behavior);
-void gcr_importer_set_prompt_behavior (GcrImporter *self,
- GcrImporterPromptBehavior behavior);
+gboolean gcr_importer_import (GcrImporter *self,
+ GInputStream *input,
+ GCancellable *cancel,
+ GError **error);
-gboolean gcr_importer_import_data (GcrImporter *self,
- const guchar *data,
- gsize n_data,
- GError *error);
+void gcr_importer_import_async (GcrImporter *self,
+ GInputStream *input,
+ GCancellable *cancel,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
-gboolean gcr_importer_import_file (GcrImporter *self,
- const gchar *filename,
- GError *error);
+gboolean gcr_importer_import_finish (GcrImporter *self,
+ GAsyncResult *res,
+ GError **error);
#endif /* __GCR_IMPORTER_H__ */
diff --git a/gcr/gcr-internal.h b/gcr/gcr-internal.h
index daad990..a8a4651 100644
--- a/gcr/gcr-internal.h
+++ b/gcr/gcr-internal.h
@@ -1,8 +1,14 @@
#ifndef GCR_INTERNAL_H_
#define GCR_INTERNAL_H_
+#include "gcr.h"
+
+#include "gp11/gp11.h"
+
#include <glib.h>
-void _gcr_initialize (void);
+void _gcr_initialize (void);
+
+GList* _gcr_get_pkcs11_modules (void);
#endif /* GCR_INTERNAL_H_ */
diff --git a/gcr/gcr-internal.c b/gcr/gcr-library.c
index 8daddee..41356b5 100644
--- a/gcr/gcr-internal.c
+++ b/gcr/gcr-library.c
@@ -21,12 +21,95 @@
#include "config.h"
+#include "gcr.h"
+#include "gcr-types.h"
#include "gcr-internal.h"
#include "egg/egg-secure-memory.h"
#include <gcrypt.h>
+static GList *all_modules = NULL;
+
+GQuark
+gcr_data_error_get_domain (void)
+{
+ static GQuark domain = 0;
+ if (domain == 0)
+ domain = g_quark_from_static_string ("gcr-parser-error");
+ return domain;
+}
+
+/* -----------------------------------------------------------------------------
+ * MEMORY
+ */
+
+static gboolean do_warning = TRUE;
+#define WARNING "couldn't allocate secure memory to keep passwords " \
+ "and or keys from being written to the disk"
+
+#define ABORTMSG "The GNOME_KEYRING_PARANOID environment variable was set. " \
+ "Exiting..."
+
+static G_LOCK_DEFINE (memory_lock);
+
+/*
+ * These are called from egg-secure-memory.c to provide appropriate
+ * locking for memory between threads
+ */
+
+void
+egg_memory_lock (void)
+{
+ G_LOCK (memory_lock);
+}
+
+void
+egg_memory_unlock (void)
+{
+ G_UNLOCK (memory_lock);
+}
+
+void*
+egg_memory_fallback (void *p, unsigned long sz)
+{
+ const gchar *env;
+
+ /* We were asked to free memory */
+ if (!sz) {
+ g_free (p);
+ return NULL;
+ }
+
+ /* We were asked to allocate */
+ if (!p) {
+ if (do_warning) {
+ g_message (WARNING);
+ do_warning = FALSE;
+ }
+
+ env = g_getenv ("GNOME_KEYRING_PARANOID");
+ if (env && *env)
+ g_error (ABORTMSG);
+
+ return g_malloc0 (sz);
+ }
+
+ /*
+ * Reallocation is a bit of a gray area, as we can be asked
+ * by external libraries (like libgcrypt) to reallocate a
+ * non-secure block into secure memory. We cannot satisfy
+ * this request (as we don't know the size of the original
+ * block) so we just try our best here.
+ */
+
+ return g_realloc (p, sz);
+}
+
+/* ------------------------------------------------------------------------------
+ * GCRYPT HOOKS
+ */
+
static void
log_handler (gpointer unused, int unknown, const gchar *msg, va_list va)
{
@@ -88,10 +171,12 @@ static struct gcry_thread_cbs glib_thread_cbs = {
void
_gcr_initialize (void)
{
- static gsize gcrypt_initialized = FALSE;
+ static volatile gsize gcr_initialized = 0;
+ GP11Module *module;
+ GError *error = NULL;
unsigned seed;
- if (g_once_init_enter (&gcrypt_initialized)) {
+ if (g_once_init_enter (&gcr_initialized)) {
/* Only initialize libgcrypt if it hasn't already been initialized */
if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) {
@@ -111,6 +196,20 @@ _gcr_initialize (void)
gcry_create_nonce (&seed, sizeof (seed));
srand (seed);
- g_once_init_leave (&gcrypt_initialized, 1);
+ /* TODO: This needs reworking for multiple modules */
+ module = gp11_module_initialize (PKCS11_MODULE_PATH, NULL, &error);
+ if (module)
+ all_modules = g_list_prepend (all_modules, module);
+ else
+ g_warning ("couldn't initialize PKCS#11 module: %s",
+ error && error->message ? error->message : "");
+
+ g_once_init_leave (&gcr_initialized, 1);
}
}
+
+GList*
+_gcr_get_pkcs11_modules (void)
+{
+ return all_modules;
+}
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index 7348788..505f9f9 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -263,7 +263,7 @@ enum_next_password (GcrParser *self, PasswordState *state, const gchar **passwor
++state->ask_state;
if (!result)
- return GCR_PARSE_CANCELLED;
+ return GCR_ERROR_CANCELLED;
/* Return any passwords added */
if (state->seen < self->pv->passwords->len) {
@@ -273,7 +273,7 @@ enum_next_password (GcrParser *self, PasswordState *state, const gchar **passwor
return SUCCESS;
}
- return GCR_PARSE_LOCKED;
+ return GCR_ERROR_LOCKED;
}
static void
@@ -293,7 +293,7 @@ parsed_fire (GcrParser *self)
static gint
parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
{
- gint res = GCR_PARSE_UNRECOGNIZED;
+ gint res = GCR_ERROR_UNRECOGNIZED;
ASN1_TYPE asn = ASN1_TYPE_EMPTY;
guint version;
@@ -303,14 +303,14 @@ parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
parsed_clear (self, CKO_PRIVATE_KEY);
parsed_ulong (self, CKA_KEY_TYPE, CKK_RSA);
- res = GCR_PARSE_FAILURE;
+ res = GCR_ERROR_FAILURE;
if (!egg_asn1_read_uint (asn, "version", &version))
goto done;
/* We only support simple version */
if (version != 0) {
- res = GCR_PARSE_UNRECOGNIZED;
+ res = GCR_ERROR_UNRECOGNIZED;
g_message ("unsupported version of RSA key: %u", version);
goto done;
}
@@ -330,7 +330,7 @@ done:
if (asn)
asn1_delete_structure (&asn);
- if (res == GCR_PARSE_FAILURE)
+ if (res == GCR_ERROR_FAILURE)
g_message ("invalid RSA key");
return res;
@@ -343,7 +343,7 @@ done:
static gint
parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
{
- gint ret = GCR_PARSE_UNRECOGNIZED;
+ gint ret = GCR_ERROR_UNRECOGNIZED;
int res;
ASN1_TYPE asn;
@@ -353,7 +353,7 @@ parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
parsed_clear (self, CKO_PRIVATE_KEY);
parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA);
- res = GCR_PARSE_FAILURE;
+ res = GCR_ERROR_FAILURE;
if (!parsed_asn1_attribute (self, asn, data, n_data, "p", CKA_PRIME) ||
!parsed_asn1_attribute (self, asn, data, n_data, "q", CKA_SUBPRIME) ||
@@ -368,7 +368,7 @@ done:
if (asn)
asn1_delete_structure (&asn);
- if (ret == GCR_PARSE_FAILURE)
+ if (ret == GCR_ERROR_FAILURE)
g_message ("invalid DSA key");
return ret;
@@ -378,7 +378,7 @@ static gint
parse_der_private_key_dsa_parts (GcrParser *self, const guchar *keydata, gsize n_keydata,
const guchar *params, gsize n_params)
{
- gint ret = GCR_PARSE_UNRECOGNIZED;
+ gint ret = GCR_ERROR_UNRECOGNIZED;
int res;
ASN1_TYPE asn_params = ASN1_TYPE_EMPTY;
ASN1_TYPE asn_key = ASN1_TYPE_EMPTY;
@@ -390,7 +390,7 @@ parse_der_private_key_dsa_parts (GcrParser *self, const guchar *keydata, gsize n
parsed_clear (self, CKO_PRIVATE_KEY);
parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA);
- res = GCR_PARSE_FAILURE;
+ res = GCR_ERROR_FAILURE;
if (!parsed_asn1_attribute (self, asn_params, params, n_params, "p", CKA_PRIME) ||
!parsed_asn1_attribute (self, asn_params, params, n_params, "q", CKA_SUBPRIME) ||
@@ -407,7 +407,7 @@ done:
if (asn_params)
asn1_delete_structure (&asn_params);
- if (ret == GCR_PARSE_FAILURE)
+ if (ret == GCR_ERROR_FAILURE)
g_message ("invalid DSA key");
return ret;
@@ -423,7 +423,7 @@ parse_der_private_key (GcrParser *self, const guchar *data, gsize n_data)
gint res;
res = parse_der_private_key_rsa (self, data, n_data);
- if (res == GCR_PARSE_UNRECOGNIZED)
+ if (res == GCR_ERROR_UNRECOGNIZED)
res = parse_der_private_key_dsa (self, data, n_data);
return res;
@@ -445,13 +445,13 @@ parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
const guchar *params;
gsize n_params;
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
asn = egg_asn1_decode ("PKIX1.pkcs-8-PrivateKeyInfo", data, n_data);
if (!asn)
goto done;
- ret = GCR_PARSE_FAILURE;
+ ret = GCR_ERROR_FAILURE;
key_type = GP11_INVALID;
key_algo = egg_asn1_read_oid (asn, "privateKeyAlgorithm.algorithm");
@@ -463,7 +463,7 @@ parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
key_type = CKK_DSA;
if (key_type == GP11_INVALID) {
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
goto done;
}
@@ -487,17 +487,17 @@ done:
ret = parse_der_private_key_dsa (self, keydata, n_keydata);
/* Otherwise try the two part format that everyone seems to like */
- if (ret == GCR_PARSE_UNRECOGNIZED && params && n_params)
+ if (ret == GCR_ERROR_UNRECOGNIZED && params && n_params)
ret = parse_der_private_key_dsa_parts (self, keydata, n_keydata,
params, n_params);
break;
default:
g_message ("invalid or unsupported key type in PKCS#8 key");
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
break;
};
- } else if (ret == GCR_PARSE_FAILURE) {
+ } else if (ret == GCR_ERROR_FAILURE) {
g_message ("invalid PKCS#8 key");
}
@@ -521,13 +521,13 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
const gchar *password;
gint l;
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
asn = egg_asn1_decode ("PKIX1.pkcs-8-EncryptedPrivateKeyInfo", data, n_data);
if (!asn)
goto done;
- ret = GCR_PARSE_FAILURE;
+ ret = GCR_ERROR_FAILURE;
/* Figure out the type of encryption */
scheme = egg_asn1_read_oid (asn, "encryptionAlgorithm.algorithm");
@@ -576,7 +576,7 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
egg_secure_free (crypted);
crypted = NULL;
- if (r != GCR_PARSE_UNRECOGNIZED) {
+ if (r != GCR_ERROR_UNRECOGNIZED) {
ret = r;
break;
}
@@ -600,7 +600,7 @@ parse_der_pkcs8 (GcrParser *self, const guchar *data, gsize n_data)
gint ret;
ret = parse_der_pkcs8_plain (self, data, n_data);
- if (ret == GCR_PARSE_UNRECOGNIZED)
+ if (ret == GCR_ERROR_UNRECOGNIZED)
ret = parse_der_pkcs8_encrypted (self, data, n_data);
return ret;
@@ -618,7 +618,7 @@ parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
asn = egg_asn1_decode ("PKIX1.Certificate", data, n_data);
if (asn == NULL)
- return GCR_PARSE_UNRECOGNIZED;
+ return GCR_ERROR_UNRECOGNIZED;
parsed_clear (self, CKO_CERTIFICATE);
parsed_ulong (self, CKA_CERTIFICATE_TYPE, CKC_X_509);
@@ -651,13 +651,13 @@ handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data)
gsize n_certificate;
int i;
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
asn = egg_asn1_decode ("PKIX1.pkcs-7-SignedData", data, n_data);
if (!asn)
goto done;
- ret = GCR_PARSE_FAILURE;
+ ret = GCR_ERROR_FAILURE;
for (i = 0; TRUE; ++i) {
@@ -694,13 +694,13 @@ parse_der_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
gsize n_content;
GQuark oid;
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
asn = egg_asn1_decode ("PKIX1.pkcs-7-ContentInfo", data, n_data);
if (!asn)
goto done;
- ret = GCR_PARSE_FAILURE;
+ ret = GCR_ERROR_FAILURE;
oid = egg_asn1_read_oid (asn, "contentType");
if (!oid)
@@ -736,13 +736,13 @@ handle_pkcs12_cert_bag (GcrParser *self, const guchar *data, gsize n_data)
gsize n_certificate;
gint ret;
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
asn = egg_asn1_decode ("PKIX1.pkcs-12-CertBag", data, n_data);
if (!asn)
goto done;
- ret = GCR_PARSE_FAILURE;
+ ret = GCR_ERROR_FAILURE;
certificate = egg_asn1_read_content (asn, data, n_data, "certValue", &n_certificate);
if (!certificate)
@@ -775,13 +775,13 @@ handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
const guchar *element;
gsize n_element;
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
asn = egg_asn1_decode ("PKIX1.pkcs-12-SafeContents", data, n_data);
if (!asn)
goto done;
- ret = GCR_PARSE_FAILURE;
+ ret = GCR_ERROR_FAILURE;
/* Get the number of elements in this bag */
res = asn1_number_of_elements (asn, "", &count);
@@ -822,10 +822,10 @@ handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
/* TODO: OID_PKCS12_BAG_CRL */
} else {
- r = GCR_PARSE_UNRECOGNIZED;
+ r = GCR_ERROR_UNRECOGNIZED;
}
- if (r == GCR_PARSE_FAILURE || r == GCR_PARSE_CANCELLED) {
+ if (r == GCR_ERROR_FAILURE || r == GCR_ERROR_CANCELLED) {
ret = r;
goto done;
}
@@ -855,13 +855,13 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
gint ret, r;
gint l;
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
asn = egg_asn1_decode ("PKIX1.pkcs-7-EncryptedData", data, n_data);
if (!asn)
goto done;
- ret = GCR_PARSE_FAILURE;
+ ret = GCR_ERROR_FAILURE;
/* Check the encryption schema OID */
scheme = egg_asn1_read_oid (asn, "encryptedContentInfo.contentEncryptionAlgorithm.algorithm");
@@ -887,7 +887,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
/* Parse the encryption stuff into a cipher. */
if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih)) {
- ret = GCR_PARSE_FAILURE;
+ ret = GCR_ERROR_FAILURE;
goto done;
}
@@ -915,7 +915,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
egg_secure_free (crypted);
crypted = NULL;
- if (r != GCR_PARSE_UNRECOGNIZED) {
+ if (r != GCR_ERROR_UNRECOGNIZED) {
ret = r;
break;
}
@@ -944,13 +944,13 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
GQuark oid;
guint i;
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
asn = egg_asn1_decode ("PKIX1.pkcs-12-AuthenticatedSafe", data, n_data);
if (!asn)
goto done;
- ret = GCR_PARSE_FAILURE;
+ ret = GCR_ERROR_FAILURE;
/*
* Inside each PKCS12 safe there are multiple bags.
@@ -992,10 +992,10 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
/* Hmmmm, not sure what this is */
} else {
g_warning ("unrecognized type of safe content in pkcs12: %s", g_quark_to_string (oid));
- r = GCR_PARSE_UNRECOGNIZED;
+ r = GCR_ERROR_UNRECOGNIZED;
}
- if (r == GCR_PARSE_FAILURE || r == GCR_PARSE_CANCELLED) {
+ if (r == GCR_ERROR_FAILURE || r == GCR_ERROR_CANCELLED) {
ret = r;
goto done;
}
@@ -1019,7 +1019,7 @@ parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
gsize n_content;
GQuark oid;
- ret = GCR_PARSE_UNRECOGNIZED;
+ ret = GCR_ERROR_UNRECOGNIZED;
asn = egg_asn1_decode ("PKIX1.pkcs-12-PFX", data, n_data);
if (!asn)
@@ -1091,14 +1091,14 @@ handle_plain_pem (GcrParser *self, GQuark type, gint subformat,
format_id = GCR_FORMAT_DER_PKCS12;
else
- return GCR_PARSE_UNRECOGNIZED;
+ return GCR_ERROR_UNRECOGNIZED;
if (subformat != 0 && subformat != format_id)
- return GCR_PARSE_UNRECOGNIZED;
+ return GCR_ERROR_UNRECOGNIZED;
format = parser_format_lookup (format_id);
if (format == NULL)
- return GCR_PARSE_UNRECOGNIZED;
+ return GCR_ERROR_UNRECOGNIZED;
return (format->function) (self, data, n_data);
}
@@ -1143,7 +1143,7 @@ handle_encrypted_pem (GcrParser *self, GQuark type, gint subformat,
val = g_hash_table_lookup (headers, "DEK-Info");
if (!val) {
g_message ("missing encryption header");
- return GCR_PARSE_FAILURE;
+ return GCR_ERROR_FAILURE;
}
/* Fill in information necessary for prompting */
@@ -1162,7 +1162,7 @@ handle_encrypted_pem (GcrParser *self, GQuark type, gint subformat,
ret = egg_openssl_decrypt_block (val, password, -1, data, n_data,
&decrypted, &n_decrypted);
if (!ret)
- return GCR_PARSE_FAILURE;
+ return GCR_ERROR_FAILURE;
g_assert (decrypted);
@@ -1176,11 +1176,11 @@ handle_encrypted_pem (GcrParser *self, GQuark type, gint subformat,
egg_secure_free (decrypted);
/* Unrecognized is a bad password */
- if (res != GCR_PARSE_UNRECOGNIZED)
+ if (res != GCR_ERROR_UNRECOGNIZED)
return res;
}
- return GCR_PARSE_FAILURE;
+ return GCR_ERROR_FAILURE;
}
typedef struct {
@@ -1194,12 +1194,12 @@ handle_pem_data (GQuark type, const guchar *data, gsize n_data,
GHashTable *headers, gpointer user_data)
{
HandlePemArgs *args = (HandlePemArgs*)user_data;
- gint res = GCR_PARSE_FAILURE;
+ gint res = GCR_ERROR_FAILURE;
gboolean encrypted = FALSE;
const gchar *val;
/* Something already failed to parse */
- if (args->result == GCR_PARSE_FAILURE)
+ if (args->result == GCR_ERROR_FAILURE)
return;
/* See if it's encrypted PEM all openssl like*/
@@ -1216,8 +1216,8 @@ handle_pem_data (GQuark type, const guchar *data, gsize n_data,
res = handle_plain_pem (args->parser, type, args->subformat,
data, n_data);
- if (res != GCR_PARSE_UNRECOGNIZED) {
- if (args->result == GCR_PARSE_UNRECOGNIZED)
+ if (res != GCR_ERROR_UNRECOGNIZED) {
+ if (args->result == GCR_ERROR_UNRECOGNIZED)
args->result = res;
else if (res > args->result)
args->result = res;
@@ -1227,16 +1227,16 @@ handle_pem_data (GQuark type, const guchar *data, gsize n_data,
static gint
handle_pem_format (GcrParser *self, gint subformat, const guchar *data, gsize n_data)
{
- HandlePemArgs ctx = { self, GCR_PARSE_UNRECOGNIZED, subformat };
+ HandlePemArgs ctx = { self, GCR_ERROR_UNRECOGNIZED, subformat };
guint found;
if (n_data == 0)
- return GCR_PARSE_UNRECOGNIZED;
+ return GCR_ERROR_UNRECOGNIZED;
found = egg_openssl_pem_parse (data, n_data, handle_pem_data, &ctx);
if (found == 0)
- return GCR_PARSE_UNRECOGNIZED;
+ return GCR_ERROR_UNRECOGNIZED;
return ctx.result;
}
@@ -1375,7 +1375,7 @@ parser_format_foreach (gpointer key, gpointer value, gpointer data)
g_assert (GCR_IS_PARSER (args->parser));
result = (format->function) (args->parser, args->data, args->n_data);
- if (result != GCR_PARSE_UNRECOGNIZED) {
+ if (result != GCR_ERROR_UNRECOGNIZED) {
args->result = result;
return TRUE;
}
@@ -1534,15 +1534,6 @@ gcr_parser_new (void)
return g_object_new (GCR_TYPE_PARSER, NULL);
}
-GQuark
-gcr_parser_get_error_domain (void)
-{
- static GQuark domain = 0;
- if (domain == 0)
- domain = g_quark_from_static_string ("gcr-parser-error");
- return domain;
-}
-
void
gcr_parser_add_password (GcrParser *self, const gchar *password)
{
@@ -1554,7 +1545,7 @@ gboolean
gcr_parser_parse_data (GcrParser *self, const guchar *data,
gsize n_data, GError **err)
{
- ForeachArgs args = { self, data, n_data, GCR_PARSE_UNRECOGNIZED };
+ ForeachArgs args = { self, data, n_data, GCR_ERROR_UNRECOGNIZED };
const gchar *message;
gint i;
@@ -1578,16 +1569,16 @@ gcr_parser_parse_data (GcrParser *self, const guchar *data,
switch (args.result) {
case SUCCESS:
return TRUE;
- case GCR_PARSE_CANCELLED:
+ case GCR_ERROR_CANCELLED:
message = _("The operation was cancelled");
break;
- case GCR_PARSE_UNRECOGNIZED:
+ case GCR_ERROR_UNRECOGNIZED:
message = _("Unrecognized or unsupported data.");
break;
- case GCR_PARSE_FAILURE:
+ case GCR_ERROR_FAILURE:
message = _("Could not parse invalid or corrupted data.");
break;
- case GCR_PARSE_LOCKED:
+ case GCR_ERROR_LOCKED:
message = _("The data is locked");
break;
default:
@@ -1595,37 +1586,11 @@ gcr_parser_parse_data (GcrParser *self, const guchar *data,
break;
};
- g_set_error_literal (err, GCR_PARSER_ERROR, args.result, message);
+ g_set_error_literal (err, GCR_DATA_ERROR, args.result, message);
return FALSE;
}
gboolean
-gcr_parser_parse_file (GcrParser *self, const gchar *filename, GError **err)
-{
- GMappedFile *mapped;
- gboolean ret;
- const guchar *data;
- gsize n_data;
-
- g_return_val_if_fail (GCR_IS_PARSER (self), FALSE);
- g_return_val_if_fail (filename, FALSE);
- g_return_val_if_fail (!err || !*err, FALSE);
-
- mapped = g_mapped_file_new (filename, FALSE, err);
- if (mapped == NULL)
- return FALSE;
-
- data = (const guchar*)g_mapped_file_get_contents (mapped);
- n_data = g_mapped_file_get_length (mapped);
-
- ret = gcr_parser_parse_data (self, data, n_data, err);
-
- g_mapped_file_free (mapped);
-
- return ret;
-}
-
-gboolean
gcr_parser_format_enable (GcrParser *self, gint format_id)
{
ParserFormat *format;
diff --git a/gcr/gcr-parser.h b/gcr/gcr-parser.h
index 4038cf0..2f5be35 100644
--- a/gcr/gcr-parser.h
+++ b/gcr/gcr-parser.h
@@ -22,12 +22,12 @@
#ifndef __GCR_PARSER_H__
#define __GCR_PARSER_H__
+#include "gcr.h"
+
#include <glib-object.h>
#include "gcr-types.h"
-#define GCR_PARSER_ERROR (gcr_parser_get_error_domain ())
-
#define GCR_TYPE_PARSER (gcr_parser_get_type ())
#define GCR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PARSER, GcrParser))
#define GCR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_PARSER, GcrParserClass))
@@ -56,37 +56,31 @@ struct _GcrParserClass {
void (*parsed) (GcrParser *self);
};
-GType gcr_parser_get_type (void);
-
-GQuark gcr_parser_get_error_domain (void) G_GNUC_CONST;
-
-GcrParser* gcr_parser_new (void);
+GType gcr_parser_get_type (void);
-gboolean gcr_parser_format_enable (GcrParser *self,
- gint format);
+GcrParser* gcr_parser_new (void);
-gboolean gcr_parser_format_disable (GcrParser *self,
- gint format);
+gboolean gcr_parser_format_enable (GcrParser *self,
+ gint format);
-gboolean gcr_parser_format_supported (GcrParser *self,
- gint format);
+gboolean gcr_parser_format_disable (GcrParser *self,
+ gint format);
-gboolean gcr_parser_parse_data (GcrParser *self,
- const guchar *data,
- gsize n_data,
- GError **err);
+gboolean gcr_parser_format_supported (GcrParser *self,
+ gint format);
-gboolean gcr_parser_parse_file (GcrParser *self,
- const gchar *filename,
- GError **err);
+gboolean gcr_parser_parse_data (GcrParser *self,
+ const guchar *data,
+ gsize n_data,
+ GError **err);
-void gcr_parser_add_password (GcrParser *self,
- const gchar *password);
+void gcr_parser_add_password (GcrParser *self,
+ const gchar *password);
-const gchar* gcr_parser_get_parsed_label (GcrParser *self);
+const gchar* gcr_parser_get_parsed_label (GcrParser *self);
-const gchar* gcr_parser_get_parsed_description (GcrParser *self);
+const gchar* gcr_parser_get_parsed_description (GcrParser *self);
-GP11Attributes* gcr_parser_get_parsed_attributes (GcrParser *self);
+struct _GP11Attributes* gcr_parser_get_parsed_attributes (GcrParser *self);
#endif /* __GCR_PARSER_H__ */
diff --git a/gcr/gcr-types.h b/gcr/gcr-types.h
index 5f12892..ca2ed91 100644
--- a/gcr/gcr-types.h
+++ b/gcr/gcr-types.h
@@ -1,11 +1,15 @@
#ifndef GCRTYPES_H_
#define GCRTYPES_H_
+#define GCR_DATA_ERROR (gcr_data_error_get_domain ())
+
+GQuark gcr_data_error_get_domain (void) G_GNUC_CONST;
+
enum {
- GCR_PARSE_FAILURE = -1,
- GCR_PARSE_UNRECOGNIZED = 1,
- GCR_PARSE_CANCELLED = 2,
- GCR_PARSE_LOCKED = 3
+ GCR_ERROR_FAILURE = -1,
+ GCR_ERROR_UNRECOGNIZED = 1,
+ GCR_ERROR_CANCELLED = 2,
+ GCR_ERROR_LOCKED = 3
};
enum {
@@ -35,11 +39,8 @@ enum {
GCR_FORMAT_PEM_PKCS12
};
-#ifndef GP11_H
-
/* Forward declare some of the GP11 objects */
-typedef struct _GP11Attributes GP11Attributes;
-
-#endif /* GP11_H */
+struct _GP11Attributes;
+struct _GP11Slot;
#endif /* GCRTYPES_H_ */
diff --git a/gcr/gcr.h b/gcr/gcr.h
new file mode 100644
index 0000000..4cf2f23
--- /dev/null
+++ b/gcr/gcr.h
@@ -0,0 +1,46 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * 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 __GCR_H__
+#define __GCR_H__
+
+#include <glib.h>
+
+#ifndef GCR_API_SUBJECT_TO_CHANGE
+#error "This API has not yet reached stability."
+#endif
+
+struct _GP11Slot;
+
+#ifdef UNIMPLEMENTED
+enum {
+ GCR_INIT_NO_MODULES = 0x01,
+};
+
+void gcr_initialize (guint flags);
+
+void gcr_modules_register_loaded (gpointer funcs);
+
+gboolean gcr_modules_register_file (const gchar *module_path,
+ GError *error);
+#endif /* UNIMPLEMENTED */
+
+#endif /* __GCR_H__ */
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index 63b89d8..4306474 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -8,6 +8,10 @@ UNIT_PROMPT =
UNIT_LIBS = \
$(top_builddir)/gcr/libgcr.la \
$(top_builddir)/egg/libegg.la \
+ $(top_builddir)/egg/libegg-secure-entry.la \
$(top_builddir)/gp11/libgp11.la
+UNIT_FLAGS = \
+ -DGCR_API_SUBJECT_TO_CHANGE
+
include $(top_srcdir)/tests/gtest.make
diff --git a/gcr/tests/unit-test-parser.c b/gcr/tests/unit-test-parser.c
index 70c11bc..3a60489 100644
--- a/gcr/tests/unit-test-parser.c
+++ b/gcr/tests/unit-test-parser.c
@@ -29,6 +29,8 @@
#include "gcr/gcr-parser.h"
+#include "gp11/gp11.h"
+
#include <glib.h>
#include <gcrypt.h>
#include <libtasn1.h>