[gnome-settings-daemon/wip/smartcard: 3/3] smartcard: land first cut



commit b95fd13014d35e5854d349beaffd6a541e55e2c7
Author: Ray Strode <rstrode redhat com>
Date:   Tue May 28 09:22:39 2013 -0400

    smartcard: land first cut

 .gitignore                                      |    6 +
 plugins/smartcard/Makefile.am                   |  104 +++
 plugins/smartcard/gsd-smartcard-enum-types.c.in |   42 ++
 plugins/smartcard/gsd-smartcard-enum-types.h.in |   24 +
 plugins/smartcard/gsd-smartcard-manager.c       |  760 ++++++++++++++++++++++
 plugins/smartcard/gsd-smartcard-manager.h       |   70 ++
 plugins/smartcard/gsd-smartcard-plugin.c        |   30 +
 plugins/smartcard/gsd-smartcard-private.h       |   25 +
 plugins/smartcard/gsd-smartcard-service.c       |  777 +++++++++++++++++++++++
 plugins/smartcard/gsd-smartcard-service.h       |   81 +++
 plugins/smartcard/gsd-smartcard-utils.c         |  199 ++++++
 plugins/smartcard/gsd-smartcard-utils.h         |   34 +
 plugins/smartcard/org.gnome.Smartcard.xml       |   93 +++
 plugins/smartcard/test-smartcard.c              |    7 +
 14 files changed, 2252 insertions(+), 0 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 5fa6217..cd37ecc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,12 @@ plugins/media-keys/gsd-marshal.h
 plugins/media-keys/gsd-media-keys-manager-glue.h
 plugins/media-keys/test-media-keys
 plugins/media-keys/test-media-window
+plugins/smartcard/gsd-smartcard-enum-types.c
+plugins/smartcard/gsd-smartcard-enum-types.h
+plugins/smartcard/gsd-smartcard.h
+plugins/smartcard/gsd-test-smartcard
+plugins/smartcard/org.gnome.Smartcard.c
+plugins/smartcard/org.gnome.Smartcard.h
 plugins/mouse/gsd-locate-pointer
 plugins/xrandr/gsd-xrandr-manager-glue.h
 plugins/xsettings/test-gtk-modules
diff --git a/plugins/smartcard/Makefile.am b/plugins/smartcard/Makefile.am
new file mode 100644
index 0000000..994ecd3
--- /dev/null
+++ b/plugins/smartcard/Makefile.am
@@ -0,0 +1,104 @@
+plugin_name = smartcard
+libsmartcard_headers = gsd-smartcard-utils.h   \
+                      gsd-smartcard-manager.h
+dbus_built_sources = org.gnome.Smartcard.c org.gnome.Smartcard.h
+enum_built_sources = gsd-smartcard-enum-types.h gsd-smartcard-enum-types.c
+BUILT_SOURCES = $(dbus_built_sources) $(enum_built_sources)
+
+libexec_PROGRAMS = gsd-test-smartcard
+
+plugin_LTLIBRARIES = \
+       libsmartcard.la
+
+$(dbus_built_sources) : Makefile.am org.gnome.Smartcard.xml
+       $(AM_V_GEN) gdbus-codegen \
+       --interface-prefix org.gnome.Smartcard. \
+       --c-namespace GsdSmartcardService \
+       --c-generate-object-manager \
+       --generate-c-code org.gnome.Smartcard \
+       org.gnome.Smartcard.xml
+
+gsd-smartcard-enum-types.h: gsd-smartcard-enum-types.h.in $(libsmartcard_headers)
+       $(AM_V_GEN) $(GLIB_MKENUMS) --template $^ > $@
+
+gsd-smartcard-enum-types.c: gsd-smartcard-enum-types.c.in $(libsmartcard_headers)
+       $(AM_V_GEN) $(GLIB_MKENUMS) --template $^ > $@
+
+gsd_test_smartcard_SOURCES =   \
+       $(dbus_built_sources)   \
+       $(enum_built_sources)   \
+       gsd-smartcard-service.c \
+       gsd-smartcard-utils.c   \
+       gsd-smartcard-manager.c \
+       test-smartcard.c
+
+gsd_test_smartcard_CPPFLAGS =                                  \
+       -I$(top_srcdir)/data/                                   \
+       -I$(top_srcdir)/gnome-settings-daemon                   \
+       -I$(top_srcdir)/plugins/common                          \
+       -DSYSCONFDIR=\""$(sysconfdir)"\"                        \
+       -DLIBDIR=\""$(libdir)"\"                                \
+       -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\"      \
+       -DGSD_SMARTCARD_MANAGER_NSS_DB=\""$(NSS_DATABASE)"\"    \
+       $(AM_CPPFLAGS)
+
+gsd_test_smartcard_CFLAGS =                                    \
+        $(PLUGIN_CFLAGS)                                       \
+        $(SETTINGS_PLUGIN_CFLAGS)                              \
+        $(MEDIA_KEYS_CFLAGS)                                   \
+        $(NSS_CFLAGS)                                          \
+        $(AM_CFLAGS)
+
+gsd_test_smartcard_LDADD =                                     \
+       $(top_builddir)/gnome-settings-daemon/libgsd.la         \
+       $(top_builddir)/plugins/common/libcommon.la             \
+       $(NSS_LIBS)                                             \
+       $(SETTINGS_DAEMON_LIBS)                                 \
+       $(SETTINGS_PLUGIN_LIBS)
+
+
+libsmartcard_la_SOURCES = \
+       $(libsmartcard_headers) \
+       $(dbus_built_sources) \
+       $(enum_built_sources) \
+       gsd-smartcard-plugin.c  \
+       gsd-smartcard-service.c \
+       gsd-smartcard-utils.c   \
+       gsd-smartcard-manager.c
+
+libsmartcard_la_CPPFLAGS = \
+       -I$(top_srcdir)/gnome-settings-daemon \
+       -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+       -DSYSCONFDIR=\""$(sysconfdir)"\" \
+       -DLIBDIR=\""$(libdir)"\" \
+       -DGSD_SMARTCARD_MANAGER_NSS_DB=\""$(NSS_DATABASE)"\" \
+       $(AM_CPPFLAGS)
+
+libsmartcard_la_CFLAGS = \
+       $(PLUGIN_CFLAGS)        \
+       $(SETTINGS_PLUGIN_CFLAGS) \
+       $(NSS_CFLAGS)   \
+       $(AM_CFLAGS)
+
+libsmartcard_la_LDFLAGS = \
+       $(GSD_PLUGIN_LDFLAGS)
+
+libsmartcard_la_LIBADD = \
+       $(SETTINGS_PLUGIN_LIBS) \
+       $(NSS_LIBS)
+
+ GSD_INTLTOOL_PLUGIN_RULE@
+
+plugin_in_files = \
+       smartcard.gnome-settings-plugin.in
+
+plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin)
+
+EXTRA_DIST = \
+       $(plugin_in_files)
+
+CLEANFILES = \
+       $(plugin_DATA)
+
+DISTCLEANFILES = \
+       $(plugin_DATA)
diff --git a/plugins/smartcard/gsd-smartcard-enum-types.c.in b/plugins/smartcard/gsd-smartcard-enum-types.c.in
new file mode 100644
index 0000000..f281cf4
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-enum-types.c.in
@@ -0,0 +1,42 @@
+/*** BEGIN file-header ***/
+
+#include <glib-object.h>
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+#include "@filename@"
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name _get_type (void) G_GNUC_CONST;
+
+GType
+ enum_name@_get_type (void)
+{
+ static GType etype = 0;
+
+ if (G_UNLIKELY(etype == 0)) {
+ static const G Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+
+ etype = g_ type@_register_static (g_intern_static_string ("@EnumName@"), values);
+ }
+
+ return etype;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+ /**/
+/*** END file-tail ***/
diff --git a/plugins/smartcard/gsd-smartcard-enum-types.h.in b/plugins/smartcard/gsd-smartcard-enum-types.h.in
new file mode 100644
index 0000000..79dcc3d
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-enum-types.h.in
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+#ifndef GSD_IDENTITY_ENUM_TYPES_H
+#define GSD_IDENTITY_ENUM_TYPES_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name _get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX _TYPE_@ENUMSHORT@ (@enum_name _get_type ())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* GSD_IDENTITY_ENUM_TYPES_H */
+/*** END file-tail ***/
diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c
new file mode 100644
index 0000000..c7b83e6
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-manager.c
@@ -0,0 +1,760 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ * Copyright (C) 2010,2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 <glib.h>
+#include <gio/gio.h>
+
+#include "gnome-settings-plugin.h"
+#include "gnome-settings-profile.h"
+#include "gsd-smartcard-manager.h"
+#include "gsd-smartcard-service.h"
+#include "gsd-smartcard-enum-types.h"
+#include "gsd-smartcard-utils.h"
+
+#include <prerror.h>
+#include <prinit.h>
+#include <nss.h>
+#include <pk11func.h>
+#include <secmod.h>
+#include <secerr.h>
+
+#define GSD_SMARTCARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SMARTCARD_MANAGER, 
GsdSmartcardManagerPrivate))
+
+struct GsdSmartcardManagerPrivate
+{
+        guint start_idle_id;
+        GsdSmartcardService *service;
+        GCancellable *cancellable;
+
+        GSettings *settings;
+
+        guint32 nss_is_loaded : 1;
+};
+
+#define CONF_SCHEMA "org.gnome.settings-daemon.peripherals.smartcard"
+
+static void     gsd_smartcard_manager_class_init  (GsdSmartcardManagerClass *klass);
+static void     gsd_smartcard_manager_init        (GsdSmartcardManager      *self);
+static void     gsd_smartcard_manager_finalize    (GObject                  *object);
+G_DEFINE_TYPE (GsdSmartcardManager, gsd_smartcard_manager, G_TYPE_OBJECT)
+G_DEFINE_QUARK (gsd-smartcard-manager-error, gsd_smartcard_manager_error)
+
+static gpointer manager_object = NULL;
+
+static void
+gsd_smartcard_manager_class_init (GsdSmartcardManagerClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->finalize = gsd_smartcard_manager_finalize;
+
+        gsd_dbus_register_error_domain (GSD_SMARTCARD_MANAGER_ERROR,
+                                        GSD_TYPE_SMARTCARD_MANAGER_ERROR);
+        g_type_class_add_private (klass, sizeof (GsdSmartcardManagerPrivate));
+}
+
+static void
+gsd_smartcard_manager_init (GsdSmartcardManager *self)
+{
+        self->priv = GSD_SMARTCARD_MANAGER_GET_PRIVATE (self);
+}
+
+static void
+load_nss (GsdSmartcardManager *self)
+{
+        GsdSmartcardManagerPrivate *priv = self->priv;
+        SECStatus status = SECSuccess;
+        static const guint32 flags = NSS_INIT_READONLY
+                                   | NSS_INIT_FORCEOPEN
+                                   | NSS_INIT_NOROOTINIT
+                                   | NSS_INIT_OPTIMIZESPACE
+                                   | NSS_INIT_PK11RELOAD;
+
+        g_debug ("attempting to load NSS database '%s'",
+                 GSD_SMARTCARD_MANAGER_NSS_DB);
+
+        PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+        status = NSS_Initialize (GSD_SMARTCARD_MANAGER_NSS_DB,
+                                 "", "", SECMOD_DB, flags);
+
+        if (status != SECSuccess) {
+                gsize error_message_size;
+                char *error_message;
+
+                error_message_size = PR_GetErrorTextLength ();
+
+                if (error_message_size == 0) {
+                        g_debug ("NSS security system could not be initialized");
+                } else {
+                        error_message = g_alloca (error_message_size);
+                        PR_GetErrorText (error_message);
+
+                        g_debug ("NSS security system could not be initialized - %s",
+                                 error_message);
+                }
+                priv->nss_is_loaded = FALSE;
+                return;
+
+        }
+
+        g_debug ("NSS database '%s' loaded", GSD_SMARTCARD_MANAGER_NSS_DB);
+        priv->nss_is_loaded = TRUE;
+}
+
+static void
+unload_nss (GsdSmartcardManager *self)
+{
+        g_debug ("attempting to unload NSS security system with database '%s'",
+                 GSD_SMARTCARD_MANAGER_NSS_DB);
+
+        if (self->priv->nss_is_loaded) {
+                NSS_Shutdown ();
+                g_debug ("NSS database '%s' unloaded", GSD_SMARTCARD_MANAGER_NSS_DB);
+        } else {
+                g_debug ("NSS database '%s' already not loaded", GSD_SMARTCARD_MANAGER_NSS_DB);
+        }
+}
+
+typedef struct
+{
+        SECMODModule *driver;
+        GHashTable *smartcards;
+} WatchSmartcardsOperation;
+
+static void
+on_watch_cancelled (GCancellable             *cancellable,
+                    WatchSmartcardsOperation *operation)
+{
+        SECMOD_CancelWait (operation->driver);
+}
+
+static gboolean
+watch_one_event_from_driver (GsdSmartcardManager       *self,
+                             WatchSmartcardsOperation  *operation,
+                             GCancellable              *cancellable,
+                             GError                   **error)
+{
+        GsdSmartcardManagerPrivate *priv = self->priv;
+        PK11SlotInfo *card, *old_card;
+        CK_SLOT_ID slot_id;
+        gulong handler_id;
+        int old_slot_series = -1, slot_series;
+
+        handler_id = g_cancellable_connect (cancellable,
+                                            G_CALLBACK (on_watch_cancelled),
+                                            operation,
+                                            NULL);
+
+        card = SECMOD_WaitForAnyTokenEvent (operation->driver, 0, PR_SecondsToInterval (1));
+
+        g_cancellable_disconnect (cancellable, handler_id);
+
+        if (card == NULL) {
+                int error_code;
+
+                error_code = PORT_GetError ();
+
+                g_warning ("smartcard event function failed.");
+
+                g_set_error (error,
+                             GSD_SMARTCARD_MANAGER_ERROR,
+                             GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS,
+                             "encountered unexpected error while "
+                             "waiting for smartcard events (error %d)",
+                             error_code);
+                return FALSE;
+        }
+
+        slot_id = PK11_GetSlotID (card);
+        slot_series = PK11_GetSlotSeries (card);
+
+        old_card = g_hash_table_lookup (operation->smartcards, GINT_TO_POINTER ((int) slot_id));
+
+        /* If there is a different card in the slot now than
+         * there was before, then we need to emit a removed signal
+         * for the old card
+         */
+        if (old_card != NULL) {
+                old_slot_series = PK11_GetSlotSeries (old_card);
+
+                if (old_slot_series != slot_series) {
+                        /* Card registered with slot previously is
+                         * different than this card, so update its
+                         * exported state to track the implicit missed
+                         * removal
+                         */
+                        gsd_smartcard_service_sync_token (priv->service, old_card, cancellable);
+                }
+
+                g_hash_table_remove (operation->smartcards, GINT_TO_POINTER ((int) slot_id));
+        }
+
+        if (PK11_IsPresent (card)) {
+                g_debug ("Detected smartcard insertion event in slot %d",
+                         (int) slot_id);
+
+                g_hash_table_replace (operation->smartcards,
+                                      GINT_TO_POINTER ((int) slot_id),
+                                      PK11_ReferenceSlot (card));
+
+                gsd_smartcard_service_sync_token (priv->service, card, cancellable);
+
+        } else if (old_card == NULL) {
+                /* If the just removed smartcard is not known to us then
+                 * ignore the removal event. NSS sends a synthentic removal
+                 * event for slots that are empty at startup
+                 */
+                g_debug ("Detected slot %d is empty in reader", (int) slot_id);
+        } else {
+                g_debug ("Detected smartcard removal event in slot %d", (int) slot_id);
+                /* If the just removed smartcard is known to us then
+                 * we need to update its exported state to reflect the
+                 * removal
+                 */
+                if (old_slot_series == slot_series) {
+                        gsd_smartcard_service_sync_token (priv->service, card, cancellable);
+                }
+        }
+
+        PK11_FreeSlot (card);
+
+        return TRUE;
+}
+
+static void
+watch_smartcards_from_driver (GTask                    *task,
+                              GsdSmartcardManager      *self,
+                              WatchSmartcardsOperation *operation,
+                              GCancellable             *cancellable)
+{
+        g_debug ("watching for smartcard events");
+        while (!g_cancellable_is_cancelled (cancellable)) {
+                gboolean watch_succeeded;
+                GError *error = NULL;
+
+                watch_succeeded = watch_one_event_from_driver (self, operation, cancellable, &error);
+
+                if (!watch_succeeded) {
+                        g_task_return_error (task, error);
+                        break;
+                }
+        }
+}
+
+static void
+destroy_watch_smartcards_operation (WatchSmartcardsOperation *operation)
+{
+        SECMOD_DestroyModule (operation->driver);
+        g_hash_table_unref (operation->smartcards);
+        g_free (operation);
+}
+
+static void
+watch_smartcards_from_driver_async (GsdSmartcardManager *self,
+                                    SECMODModule        *driver,
+                                    GCancellable        *cancellable,
+                                    GAsyncReadyCallback  callback,
+                                    gpointer             user_data)
+{
+        GTask *task;
+        WatchSmartcardsOperation *operation;
+
+        operation = g_new0 (WatchSmartcardsOperation, 1);
+        operation->driver = SECMOD_ReferenceModule (driver);
+        operation->smartcards = g_hash_table_new_full (NULL,
+                                                       NULL,
+                                                       NULL,
+                                                       (GDestroyNotify)
+                                                       PK11_FreeSlot);
+
+        task = g_task_new (self, cancellable, callback, user_data);
+
+        g_task_set_task_data (task,
+                              operation,
+                              (GDestroyNotify)
+                              destroy_watch_smartcards_operation);
+
+        g_task_run_in_thread (task, (GTaskThreadFunc) watch_smartcards_from_driver);
+        g_object_unref (task);
+}
+
+typedef struct
+{
+  guint driver_registered : 1;
+  guint smartcards_watched : 1;
+} ActivateDriverOperation;
+
+static void
+try_to_complete_driver_activation (GTask *task)
+{
+        ActivateDriverOperation *operation;
+
+        operation = g_task_get_task_data (task);
+
+        if (!operation->driver_registered)
+                return;
+
+        if (!operation->smartcards_watched)
+                return;
+
+        g_task_return_boolean (task, TRUE);
+}
+
+static gboolean
+register_driver_finish (GsdSmartcardManager  *self,
+                        GAsyncResult         *result,
+                        GError              **error)
+{
+        return gsd_finish_boolean_task (G_OBJECT (self), result, error);
+}
+
+static void
+on_driver_registered (GsdSmartcardManager *self,
+                      GAsyncResult        *result,
+                      GTask               *task)
+{
+        ActivateDriverOperation *operation;
+        GError *error = NULL;
+
+        if (!register_driver_finish (self, result, &error)) {
+                g_task_return_error (task, error);
+                g_object_unref (task);
+                return;
+        }
+
+        operation = g_task_get_task_data (task);
+        operation->driver_registered = TRUE;
+
+        try_to_complete_driver_activation (task);
+}
+
+static void
+on_smartcards_from_driver_watched (GsdSmartcardManager *self,
+                                   GAsyncResult        *result,
+                                   GTask               *task)
+{
+        ActivateDriverOperation *operation;
+
+        operation = g_task_get_task_data (task);
+        operation->smartcards_watched = TRUE;
+
+        try_to_complete_driver_activation (task);
+}
+
+typedef struct {
+        SECMODModule  *driver;
+        guint          idle_id;
+        GError        *error;
+} DriverRegistrationOperation;
+
+static void
+destroy_driver_registration_operation (DriverRegistrationOperation *operation)
+{
+        SECMOD_DestroyModule (operation->driver);
+        g_free (operation);
+}
+
+static gboolean
+on_task_thread_to_complete_driver_registration (GTask *task)
+{
+        DriverRegistrationOperation *operation;
+        operation = g_task_get_task_data (task);
+
+        if (operation->error != NULL)
+                g_task_return_error (task, operation->error);
+        else
+                g_task_return_boolean (task, TRUE);
+
+        return G_SOURCE_REMOVE;
+}
+
+static gboolean
+on_main_thread_to_register_driver (GTask *task)
+{
+        GsdSmartcardManager *self;
+        GsdSmartcardManagerPrivate *priv;
+        DriverRegistrationOperation *operation;
+        GSource *source;
+
+        self = g_task_get_source_object (task);
+        priv = self->priv;
+        operation = g_task_get_task_data (task);
+
+        gsd_smartcard_service_register_driver (priv->service,
+                                               operation->driver);
+
+        source = g_idle_source_new ();
+        g_task_attach_source (task,
+                              source,
+                              (GSourceFunc)
+                              on_task_thread_to_complete_driver_registration);
+        g_source_unref (source);
+
+        return G_SOURCE_REMOVE;
+}
+
+static void
+register_driver (GsdSmartcardManager *self,
+                 SECMODModule         *driver,
+                 GCancellable         *cancellable,
+                 GAsyncReadyCallback   callback,
+                 gpointer              user_data)
+{
+        GTask *task;
+        DriverRegistrationOperation *operation;
+
+        task = g_task_new (self, cancellable, callback, user_data);
+        operation = g_new0 (DriverRegistrationOperation, 1);
+        operation->driver = SECMOD_ReferenceModule (driver);
+        g_task_set_task_data (task,
+                              operation,
+                              (GDestroyNotify)
+                              destroy_driver_registration_operation);
+
+        operation->idle_id = g_idle_add ((GSourceFunc) on_main_thread_to_register_driver, task);
+}
+
+static void
+activate_driver (GsdSmartcardManager *self,
+                 SECMODModule        *driver,
+                 GCancellable        *cancellable,
+                 GAsyncReadyCallback  callback,
+                 gpointer             user_data)
+{
+        ActivateDriverOperation *operation;
+        GTask *task;
+
+        g_debug ("Activating driver '%s'", driver->commonName);
+
+        task = g_task_new (self, cancellable, callback, user_data);
+        operation = g_new0 (ActivateDriverOperation, 1);
+        g_task_set_task_data (task, operation, (GDestroyNotify) g_free);
+
+        register_driver (self,
+                         driver,
+                         cancellable,
+                         (GAsyncReadyCallback)
+                         on_driver_registered,
+                         task);
+        watch_smartcards_from_driver_async (self,
+                                            driver,
+                                            cancellable,
+                                            (GAsyncReadyCallback)
+                                            on_smartcards_from_driver_watched,
+                                            task);
+}
+
+typedef struct
+{
+  int pending_drivers_count;
+  int activated_drivers_count;
+} ActivateAllDriversOperation;
+
+static gboolean
+activate_driver_async_finish (GsdSmartcardManager  *self,
+                              GAsyncResult         *result,
+                              GError              **error)
+{
+        return gsd_finish_boolean_task (G_OBJECT (self), result, error);
+}
+
+static void
+try_to_complete_all_drivers_activation (GTask *task)
+{
+        ActivateAllDriversOperation *operation;
+
+        operation = g_task_get_task_data (task);
+
+        if (operation->pending_drivers_count >= 0)
+                return;
+
+        if (operation->activated_drivers_count > 0)
+                g_task_return_boolean (task, TRUE);
+        else
+                g_task_return_boolean (task, FALSE);
+
+        g_object_unref (task);
+}
+
+static void
+on_driver_activated (GsdSmartcardManager *self,
+                     GAsyncResult        *result,
+                     GTask               *task)
+{
+        GError *error = NULL;
+        gboolean driver_activated;
+        ActivateAllDriversOperation *operation;
+
+        driver_activated = activate_driver_async_finish (self, result, &error);
+
+        operation = g_task_get_task_data (task);
+
+        if (driver_activated)
+                operation->activated_drivers_count++;
+
+        operation->pending_drivers_count--;
+
+        try_to_complete_all_drivers_activation (task);
+}
+
+static void
+activate_all_drivers_async (GsdSmartcardManager *self,
+                            GCancellable        *cancellable,
+                            GAsyncReadyCallback  callback,
+                            gpointer             user_data)
+{
+        GTask *task;
+        SECMODListLock *lock;
+        SECMODModuleList *driver_list, *node;
+        ActivateAllDriversOperation *operation;
+
+        task = g_task_new (self, cancellable, callback, user_data);
+        operation = g_new0 (ActivateAllDriversOperation, 1);
+        g_task_set_task_data (task, operation, (GDestroyNotify) g_free);
+
+        lock = SECMOD_GetDefaultModuleListLock ();
+
+        g_assert (lock != NULL);
+
+        SECMOD_GetReadLock (lock);
+        driver_list = SECMOD_GetDefaultModuleList ();
+        for (node = driver_list; node != NULL; node = node->next) {
+                if (!SECMOD_HasRemovableSlots (node->module) ||
+                    !node->module->loaded)
+                        continue;
+                operation->pending_drivers_count++;
+
+                activate_driver (self,
+                                 node->module,
+                                 cancellable,
+                                 (GAsyncReadyCallback)
+                                 on_driver_activated,
+                                 task);
+
+        }
+        SECMOD_ReleaseReadLock (lock);
+}
+
+static gboolean
+activate_all_drivers_async_finish (GsdSmartcardManager  *self,
+                                   GAsyncResult         *result,
+                                   GError              **error)
+{
+        return gsd_finish_boolean_task (G_OBJECT (self), result, error);
+}
+
+static void
+on_all_drivers_activated (GsdSmartcardManager *self,
+                          GAsyncResult        *result,
+                          GTask               *task)
+{
+        GError *error = NULL;
+        gboolean driver_activated;
+
+        driver_activated = activate_all_drivers_async_finish (self, result, &error);
+
+        if (!driver_activated) {
+                g_task_return_error (task, error);
+                return;
+        }
+
+        g_task_return_boolean (task, TRUE);
+}
+
+static void
+watch_smartcards (GTask               *task,
+                  GsdSmartcardManager *self,
+                  gpointer             data,
+                  GCancellable        *cancellable)
+{
+        GMainContext *context;
+        GMainLoop *loop;
+
+        g_debug ("Getting list of suitable drivers");
+        context = g_main_context_new ();
+        g_main_context_push_thread_default (context);
+
+        activate_all_drivers_async (self,
+                                    cancellable,
+                                    (GAsyncReadyCallback)
+                                    on_all_drivers_activated,
+                                    task);
+
+        loop = g_main_loop_new (context, FALSE);
+        g_main_loop_run (loop);
+        g_main_loop_unref (loop);
+
+        g_main_context_pop_thread_default (context);
+        g_main_context_unref (context);
+}
+
+static void
+watch_smartcards_async (GsdSmartcardManager *self,
+                        GCancellable        *cancellable,
+                        GAsyncReadyCallback  callback,
+                        gpointer             user_data)
+{
+        GTask *task;
+
+        task = g_task_new (self, cancellable, callback, user_data);
+
+        g_task_run_in_thread (task, (GTaskThreadFunc) watch_smartcards);
+
+        g_object_unref (task);
+}
+
+static gboolean
+watch_smartcards_async_finish (GsdSmartcardManager *self,
+                               GAsyncResult        *result,
+                               GError             **error)
+{
+        return gsd_finish_boolean_task (G_OBJECT (self), result, error);
+}
+
+static void
+on_smartcards_watched (GsdSmartcardManager *self,
+                       GAsyncResult        *result)
+{
+        GError *error = NULL;
+
+        if (!watch_smartcards_async_finish (self, result, &error)) {
+                g_debug ("Error watching smartcards: %s",
+                         error->message);
+                g_error_free (error);
+        }
+}
+
+static void
+on_service_created (GObject             *source_object,
+                    GAsyncResult        *result,
+                    GsdSmartcardManager *self)
+{
+        GsdSmartcardManagerPrivate *priv = self->priv;
+        GsdSmartcardService *service;
+        GError *error = NULL;
+
+        service = gsd_smartcard_service_new_finish (result, &error);
+
+        if (service == NULL) {
+                g_warning("Couldn't create session bus service: %s",
+                          error->message);
+                g_error_free (error);
+                return;
+        }
+
+        priv->service = service;
+
+        watch_smartcards_async (self,
+                                priv->cancellable,
+                                (GAsyncReadyCallback)
+                                on_smartcards_watched,
+                                NULL);
+
+}
+
+static gboolean
+gsd_smartcard_manager_idle_cb (GsdSmartcardManager *self)
+{
+        GsdSmartcardManagerPrivate *priv = self->priv;
+
+        gnome_settings_profile_start (NULL);
+
+        priv->cancellable = g_cancellable_new();
+        priv->settings = g_settings_new (CONF_SCHEMA);
+
+        load_nss (self);
+
+        gsd_smartcard_service_new_async (self,
+                                         priv->cancellable,
+                                         (GAsyncReadyCallback)
+                                         on_service_created,
+                                         self);
+
+        gnome_settings_profile_end (NULL);
+
+        priv->start_idle_id = 0;
+        return FALSE;
+}
+
+gboolean
+gsd_smartcard_manager_start (GsdSmartcardManager  *self,
+                             GError              **error)
+{
+        GsdSmartcardManagerPrivate *priv = self->priv;
+
+        gnome_settings_profile_start (NULL);
+
+        priv->start_idle_id = g_idle_add ((GSourceFunc) gsd_smartcard_manager_idle_cb, self);
+
+        gnome_settings_profile_end (NULL);
+
+        return TRUE;
+}
+
+void
+gsd_smartcard_manager_stop (GsdSmartcardManager *self)
+{
+        GsdSmartcardManagerPrivate *priv = self->priv;
+
+        g_debug ("Stopping smartcard manager");
+
+        unload_nss (self);
+
+        g_clear_object (&priv->settings);
+        g_clear_object (&priv->cancellable);
+}
+
+static void
+gsd_smartcard_manager_finalize (GObject *object)
+{
+        GsdSmartcardManager *self;
+        GsdSmartcardManagerPrivate *priv;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GSD_IS_SMARTCARD_MANAGER (object));
+
+        self = GSD_SMARTCARD_MANAGER (object);
+        priv = self->priv;
+
+        g_return_if_fail (self->priv != NULL);
+
+        if (priv->start_idle_id != 0)
+                g_source_remove (priv->start_idle_id);
+
+        G_OBJECT_CLASS (gsd_smartcard_manager_parent_class)->finalize (object);
+}
+
+GsdSmartcardManager *
+gsd_smartcard_manager_new (void)
+{
+        if (manager_object != NULL) {
+                g_object_ref (manager_object);
+        } else {
+                manager_object = g_object_new (GSD_TYPE_SMARTCARD_MANAGER, NULL);
+                g_object_add_weak_pointer (manager_object,
+                                           (gpointer *) &manager_object);
+        }
+
+        return GSD_SMARTCARD_MANAGER (manager_object);
+}
diff --git a/plugins/smartcard/gsd-smartcard-manager.h b/plugins/smartcard/gsd-smartcard-manager.h
new file mode 100644
index 0000000..6220793
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-manager.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 __GSD_SMARTCARD_MANAGER_H
+#define __GSD_SMARTCARD_MANAGER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_SMARTCARD_MANAGER         (gsd_smartcard_manager_get_type ())
+#define GSD_SMARTCARD_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_SMARTCARD_MANAGER, 
GsdSmartcardManager))
+#define GSD_SMARTCARD_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_SMARTCARD_MANAGER, 
GsdSmartcardManagerClass))
+#define GSD_IS_SMARTCARD_MANAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_SMARTCARD_MANAGER))
+#define GSD_IS_SMARTCARD_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_SMARTCARD_MANAGER))
+#define GSD_SMARTCARD_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_SMARTCARD_MANAGER, 
GsdSmartcardManagerClass))
+#define GSD_SMARTCARD_MANAGER_ERROR        (gsd_smartcard_manager_error_quark ())
+
+typedef struct GsdSmartcardManagerPrivate GsdSmartcardManagerPrivate;
+
+typedef struct
+{
+        GObject                     parent;
+        GsdSmartcardManagerPrivate *priv;
+} GsdSmartcardManager;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+} GsdSmartcardManagerClass;
+
+typedef enum
+{
+ GSD_SMARTCARD_MANAGER_ERROR_GENERIC = 0,
+ GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS,
+ GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
+ GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS,
+ GSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS,
+} GsdSmartcardManagerError;
+
+GType                   gsd_smartcard_manager_get_type    (void);
+GQuark                  gsd_smartcard_manager_error_quark (void);
+
+
+GsdSmartcardManager *   gsd_smartcard_manager_new         (void);
+gboolean                gsd_smartcard_manager_start       (GsdSmartcardManager  *manager,
+                                                           GError              **error);
+void                    gsd_smartcard_manager_stop        (GsdSmartcardManager  *manager);
+
+G_END_DECLS
+
+#endif /* __GSD_SMARTCARD_MANAGER_H */
diff --git a/plugins/smartcard/gsd-smartcard-plugin.c b/plugins/smartcard/gsd-smartcard-plugin.c
new file mode 100644
index 0000000..ea78f85
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-plugin.c
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "gnome-settings-plugin.h"
+#include "gsd-smartcard-manager.h"
+
+GNOME_SETTINGS_PLUGIN_REGISTER (GsdSmartcard, gsd_smartcard)
diff --git a/plugins/smartcard/gsd-smartcard-private.h b/plugins/smartcard/gsd-smartcard-private.h
new file mode 100644
index 0000000..7385740
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-private.h
@@ -0,0 +1,25 @@
+/* securitycard-private.h 
+ *
+ * Copyright (C) 2013 Ray Strode
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 GSD_SMARTCARD_PRIVATE_H
+#define GSD_SMARTCARD_PRIVATE_H
+
+G_BEGIN_DECLS
+G_END_DECLS
+#endif
diff --git a/plugins/smartcard/gsd-smartcard-service.c b/plugins/smartcard/gsd-smartcard-service.c
new file mode 100644
index 0000000..e0f4ea4
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-service.c
@@ -0,0 +1,777 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Authors: Ray Strode
+ */
+
+#include "config.h"
+
+#include "gsd-smartcard-service.h"
+#include "org.gnome.Smartcard.h"
+#include "gsd-smartcard-manager.h"
+#include "gsd-smartcard-enum-types.h"
+#include "gsd-smartcard-utils.h"
+
+#include "gnome-settings-plugin.h"
+
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+struct _GsdSmartcardServicePrivate
+{
+        GDBusConnection            *bus_connection;
+        GDBusObjectManagerServer   *object_manager_server;
+        GsdSmartcardManager        *token_manager;
+        GCancellable               *cancellable;
+        GHashTable                 *tokens;
+
+        guint name_id;
+};
+
+#define GSD_SMARTCARD_DBUS_NAME GSD_DBUS_NAME ".Smartcard"
+#define GSD_SMARTCARD_DBUS_PATH GSD_DBUS_PATH "/Smartcard"
+#define GSD_SMARTCARD_MANAGER_DBUS_PATH GSD_SMARTCARD_DBUS_PATH "/Manager"
+#define GSD_SMARTCARD_MANAGER_DRIVERS_DBUS_PATH GSD_SMARTCARD_MANAGER_DBUS_PATH "/Drivers"
+#define GSD_SMARTCARD_MANAGER_TOKENS_DBUS_PATH  GSD_SMARTCARD_MANAGER_DBUS_PATH "/Tokens"
+
+enum {
+        PROP_0,
+        PROP_MANAGER,
+        PROP_BUS_CONNECTION
+};
+
+static void gsd_smartcard_service_set_property (GObject *object,
+                                                guint property_id,
+                                                const GValue *value,
+                                                GParamSpec *param_spec);
+static void gsd_smartcard_service_get_property (GObject *object,
+                                                guint property_id,
+                                                GValue *value,
+                                                GParamSpec *param_spec);
+static void async_initable_interface_init (GAsyncInitableIface *interface);
+static void smartcard_service_manager_interface_init (GsdSmartcardServiceManagerIface *interface);
+
+G_LOCK_DEFINE_STATIC (gsd_smartcard_tokens);
+
+G_DEFINE_TYPE_WITH_CODE (GsdSmartcardService,
+                         gsd_smartcard_service,
+                         GSD_SMARTCARD_SERVICE_TYPE_MANAGER_SKELETON,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
+                                                async_initable_interface_init)
+                         G_IMPLEMENT_INTERFACE (GSD_SMARTCARD_SERVICE_TYPE_MANAGER,
+                                                smartcard_service_manager_interface_init));
+
+static void
+set_bus_connection (GsdSmartcardService  *self,
+                    GDBusConnection      *connection)
+{
+        GsdSmartcardServicePrivate *priv = self->priv;
+
+        if (priv->bus_connection != connection) {
+                g_clear_object (&priv->bus_connection);
+                priv->bus_connection = g_object_ref (connection);
+                g_object_notify (G_OBJECT (self), "bus-connection");
+        }
+}
+
+static void
+register_object_manager (GsdSmartcardService *self)
+{
+        GsdSmartcardServiceObjectSkeleton *object;
+
+        self->priv->object_manager_server = g_dbus_object_manager_server_new (GSD_SMARTCARD_DBUS_PATH);
+
+        object = gsd_smartcard_service_object_skeleton_new (GSD_SMARTCARD_MANAGER_DBUS_PATH);
+        gsd_smartcard_service_object_skeleton_set_manager (object,
+                                                           GSD_SMARTCARD_SERVICE_MANAGER (self));
+
+        g_dbus_object_manager_server_export (self->priv->object_manager_server,
+                                             G_DBUS_OBJECT_SKELETON (object));
+        g_object_unref (object);
+
+        g_dbus_object_manager_server_set_connection (self->priv->object_manager_server,
+                                                     self->priv->bus_connection);
+}
+
+static void
+on_bus_gotten (GObject      *source_object,
+               GAsyncResult *result,
+               GTask        *task)
+{
+        GsdSmartcardService *self;
+        GsdSmartcardServicePrivate *priv;
+        GDBusConnection *connection;
+        GError *error = NULL;
+
+        connection = g_bus_get_finish (result, &error);
+        if (connection == NULL) {
+                g_task_return_error (task, error);
+                goto out;
+        }
+
+        g_debug ("taking name %s on session bus",
+                 GSD_SMARTCARD_DBUS_NAME);
+
+        self = g_task_get_source_object (task);
+        priv = self->priv;
+
+        set_bus_connection (self, connection);
+
+        register_object_manager (self);
+        priv->name_id = g_bus_own_name_on_connection (connection,
+                                                      GSD_SMARTCARD_DBUS_NAME,
+                                                      G_BUS_NAME_OWNER_FLAGS_NONE,
+                                                      NULL,
+                                                      NULL,
+                                                      NULL,
+                                                      NULL);
+        g_task_return_boolean (task, TRUE);
+
+out:
+        g_object_unref (task);
+        return;
+}
+
+static gboolean
+gsd_smartcard_service_initable_init_finish (GAsyncInitable  *initable,
+                                            GAsyncResult    *result,
+                                            GError         **error)
+{
+        GTask *task;
+
+        task = G_TASK (result);
+
+        return g_task_propagate_boolean (task, error);
+}
+
+static void
+gsd_smartcard_service_initable_init_async (GAsyncInitable      *initable,
+                                           int                  io_priority,
+                                           GCancellable        *cancellable,
+                                           GAsyncReadyCallback  callback,
+                                           gpointer             user_data)
+{
+        GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (initable);
+        GTask *task;
+
+        task = g_task_new (G_OBJECT (self), cancellable, callback, user_data);
+        g_task_set_priority (task, io_priority);
+
+        g_bus_get (G_BUS_TYPE_SESSION,
+                   g_task_get_cancellable (task),
+                   (GAsyncReadyCallback)
+                   on_bus_gotten,
+                   task);
+
+}
+
+static void
+async_initable_interface_init (GAsyncInitableIface *interface)
+{
+        interface->init_async = gsd_smartcard_service_initable_init_async;
+        interface->init_finish = gsd_smartcard_service_initable_init_finish;
+}
+
+static gboolean
+gsd_smartcard_service_handle_get_login_token (GsdSmartcardServiceManager *manager,
+                                              GDBusMethodInvocation      *invocation)
+{
+  /*GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (manager);*/
+  return TRUE;
+}
+
+static gboolean
+gsd_smartcard_service_handle_get_inserted_tokens (GsdSmartcardServiceManager *manager,
+                                                  GDBusMethodInvocation      *invocation)
+{
+  /*GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (manager);*/
+  return TRUE;
+}
+
+static void
+smartcard_service_manager_interface_init (GsdSmartcardServiceManagerIface *interface)
+{
+  interface->handle_get_login_token = gsd_smartcard_service_handle_get_login_token;
+  interface->handle_get_inserted_tokens = gsd_smartcard_service_handle_get_inserted_tokens;
+}
+
+static void
+gsd_smartcard_service_init (GsdSmartcardService *self)
+{
+        self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+                                                  GSD_TYPE_SMARTCARD_SERVICE,
+                                                  GsdSmartcardServicePrivate);
+        self->priv->tokens = g_hash_table_new_full (g_str_hash,
+                                                    g_str_equal,
+                                                    (GDestroyNotify) g_free,
+                                                    NULL);
+}
+
+static void
+gsd_smartcard_service_dispose (GObject *object)
+{
+        GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (object);
+
+        g_clear_object (&self->priv->bus_connection);
+        g_clear_object (&self->priv->object_manager_server);
+        g_clear_object (&self->priv->token_manager);
+
+        g_cancellable_cancel (self->priv->cancellable);
+        g_clear_object (&self->priv->cancellable);
+        g_clear_pointer (&self->priv->tokens,
+                         (GDestroyNotify)
+                         g_hash_table_unref);
+
+        G_OBJECT_CLASS (gsd_smartcard_service_parent_class)->dispose (object);
+}
+
+static void
+gsd_smartcard_service_finalize (GObject *object)
+{
+        G_OBJECT_CLASS (gsd_smartcard_service_parent_class)->finalize (object);
+}
+
+static void
+gsd_smartcard_service_set_property (GObject      *object,
+                                    guint         property_id,
+                                    const GValue *value,
+                                    GParamSpec   *param_spec)
+{
+        GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (object);
+        GsdSmartcardServicePrivate *priv = self->priv;
+
+        switch (property_id) {
+                case PROP_MANAGER:
+                        priv->token_manager = g_value_dup_object (value);
+                        break;
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
+                        break;
+        }
+}
+
+static void
+gsd_smartcard_service_get_property (GObject    *object,
+                                    guint       property_id,
+                                    GValue     *value,
+                                    GParamSpec *param_spec)
+{
+        GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (object);
+        GsdSmartcardServicePrivate *priv = self->priv;
+
+        switch (property_id) {
+                case PROP_MANAGER:
+                        g_value_set_object (value, priv->token_manager);
+                        break;
+                case PROP_BUS_CONNECTION:
+                        g_value_set_object (value, priv->bus_connection);
+                        break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
+                        break;
+        }
+}
+
+static void
+gsd_smartcard_service_class_init (GsdSmartcardServiceClass *service_class)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (service_class);
+        GParamSpec *param_spec;
+
+        object_class->dispose = gsd_smartcard_service_dispose;
+        object_class->finalize = gsd_smartcard_service_finalize;
+        object_class->set_property = gsd_smartcard_service_set_property;
+        object_class->get_property = gsd_smartcard_service_get_property;
+
+        param_spec = g_param_spec_object ("manager",
+                                          "Smartcard Manager",
+                                          "Smartcard Manager",
+                                          GSD_TYPE_SMARTCARD_MANAGER,
+                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+        g_object_class_install_property (object_class, PROP_MANAGER, param_spec);
+        param_spec = g_param_spec_object ("bus-connection",
+                                          "Bus Connection",
+                                          "bus connection",
+                                          G_TYPE_DBUS_CONNECTION,
+                                          G_PARAM_READABLE);
+        g_object_class_install_property (object_class, PROP_BUS_CONNECTION, param_spec);
+
+        g_type_class_add_private (service_class, sizeof (GsdSmartcardServicePrivate));
+}
+
+static void
+on_new_async_finished (GObject      *source_object,
+                       GAsyncResult *result,
+                       GTask        *task)
+{
+        GError *error = NULL;
+        GObject *object;
+
+        object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
+                                              result,
+                                              &error);
+
+        if (object == NULL) {
+                g_task_return_error (task, error);
+                goto out;
+        }
+
+        g_assert (object != NULL);
+        g_assert (GSD_IS_SMARTCARD_SERVICE (object));
+
+        g_task_return_pointer (task, object, g_object_unref);
+out:
+        g_object_unref (task);
+        return;
+}
+
+void
+gsd_smartcard_service_new_async (GsdSmartcardManager *manager,
+                                 GCancellable        *cancellable,
+                                 GAsyncReadyCallback  callback,
+                                 gpointer             user_data)
+{
+        GTask *task;
+
+        task = g_task_new (NULL, cancellable, callback, user_data);
+
+        g_async_initable_new_async (GSD_TYPE_SMARTCARD_SERVICE,
+                                    G_PRIORITY_DEFAULT,
+                                    cancellable,
+                                    (GAsyncReadyCallback)
+                                    on_new_async_finished,
+                                    task,
+                                    "manager", manager,
+                                    NULL);
+}
+
+GsdSmartcardService *
+gsd_smartcard_service_new_finish (GAsyncResult  *result,
+                                  GError       **error)
+{
+        GTask *task;
+        GsdSmartcardService *self = NULL;
+
+        task = G_TASK (result);
+
+        self = g_task_propagate_pointer (task, error);
+
+        if (self == NULL)
+                goto out;
+
+        self = g_object_ref (self);
+out:
+        return self;
+}
+
+static char *
+get_object_path_for_driver (GsdSmartcardService *self,
+                            SECMODModule        *driver)
+{
+        char *object_path;
+        char *escaped_library_path;
+
+        escaped_library_path = gsd_dbus_escape_object_path (driver->dllName,
+                                                            strlen (driver->dllName));
+
+        object_path = g_build_path ("/",
+                                    GSD_SMARTCARD_MANAGER_DRIVERS_DBUS_PATH,
+                                    escaped_library_path, NULL);
+        g_free (escaped_library_path);
+
+        return object_path;
+}
+
+#if 0
+static void
+unregister_driver (GsdSmartcardService *self,
+                   SECMODModule        *driver)
+{
+        char *object_path;
+
+        object_path = get_object_path_for_driver (self, driver);
+        g_dbus_object_manager_server_unexport (self->priv->object_manager_server,
+                                               object_path);
+        g_free (object_path);
+}
+#endif
+
+void
+gsd_smartcard_service_register_driver (GsdSmartcardService  *self,
+                                       SECMODModule         *driver)
+{
+        char *object_path;
+        GDBusObjectSkeleton *object;
+        GDBusInterfaceSkeleton *interface;
+
+        object_path = get_object_path_for_driver (self, driver);
+        object = G_DBUS_OBJECT_SKELETON (gsd_smartcard_service_object_skeleton_new (object_path));
+        g_free (object_path);
+
+        interface = G_DBUS_INTERFACE_SKELETON (gsd_smartcard_service_driver_skeleton_new ());
+
+        g_dbus_object_skeleton_add_interface (object, interface);
+        g_object_unref (interface);
+
+        g_object_set (G_OBJECT (interface),
+                      "library", driver->dllName,
+                      "description", driver->commonName,
+                      NULL);
+        g_dbus_object_manager_server_export (self->priv->object_manager_server,
+                                             object);
+        g_object_unref (object);
+}
+
+static char *
+get_object_path_for_token (GsdSmartcardService *self,
+                           PK11SlotInfo        *card_slot)
+{
+        char *object_path;
+        char *escaped_library_path;
+        SECMODModule *driver;
+        CK_SLOT_ID slot_id;
+
+        driver = PK11_GetModule (card_slot);
+        slot_id = PK11_GetSlotID (card_slot);
+
+        escaped_library_path = gsd_dbus_escape_object_path (driver->dllName,
+                                                            strlen (driver->dllName));
+
+        object_path = g_strdup_printf ("%s/token_from_%s_slot_%lu",
+                                       GSD_SMARTCARD_MANAGER_TOKENS_DBUS_PATH,
+                                       escaped_library_path,
+                                       (gulong) slot_id);
+
+        return object_path;
+}
+
+static void
+synchronize_token_now (GsdSmartcardService *self,
+                       PK11SlotInfo        *card_slot)
+{
+        GsdSmartcardServicePrivate *priv = self->priv;
+        GDBusInterfaceSkeleton *interface;
+        char *object_path;
+        const char *token_name;
+        gboolean is_present, is_login_card;
+
+        object_path = get_object_path_for_token (self, card_slot);
+
+        G_LOCK (gsd_smartcard_tokens);
+        interface = g_hash_table_lookup (priv->tokens, object_path);
+        g_free (object_path);
+
+        if (interface == NULL)
+                goto out;
+
+        token_name = PK11_GetTokenName (card_slot);
+        is_present = PK11_IsPresent (card_slot);
+
+        if (g_strcmp0 (g_getenv ("PKCS11_LOGIN_TOKEN_NAME"), token_name) == 0)
+                is_login_card = TRUE;
+        else
+                is_login_card = FALSE;
+
+        g_debug ("===============================");
+        g_debug (" Token '%s'", token_name);
+        g_debug (" Inserted: %s", is_present? "yes" : "no");
+        g_debug (" Previously used to login: %s", is_login_card? "yes" : "no");
+        g_debug ("===============================\n");
+
+        g_object_set (G_OBJECT (interface),
+                      "used-to-login", is_login_card,
+                      "is-inserted", is_present,
+                      NULL);
+        g_object_get (G_OBJECT (interface),
+                      "used-to-login", &is_login_card,
+                      "is-inserted", &is_present,
+                      NULL);
+
+out:
+        G_UNLOCK (gsd_smartcard_tokens);
+}
+
+typedef struct
+{
+        PK11SlotInfo *card_slot;
+        char         *object_path;
+        GSource      *main_thread_source;
+} RegisterNewTokenOperation;
+
+static void
+destroy_register_new_token_operation (RegisterNewTokenOperation *operation)
+{
+        g_clear_pointer (&operation->main_thread_source,
+                         (GDestroyNotify)
+                         g_source_destroy);
+        PK11_FreeSlot (operation->card_slot);
+        g_free (operation->object_path);
+        g_free (operation);
+}
+
+static gboolean
+on_main_thread_to_register_new_token (GTask *task)
+{
+        GsdSmartcardService *self;
+        GsdSmartcardServicePrivate *priv;
+        GDBusObjectSkeleton *object;
+        GDBusInterfaceSkeleton *interface;
+        RegisterNewTokenOperation *operation;
+        SECMODModule *driver;
+        char *driver_object_path;
+        const char *token_name;
+
+        self = g_task_get_source_object (task);
+        priv = self->priv;
+
+        operation = g_task_get_task_data (task);
+        operation->main_thread_source = NULL;
+
+        object = G_DBUS_OBJECT_SKELETON (gsd_smartcard_service_object_skeleton_new (operation->object_path));
+        interface = G_DBUS_INTERFACE_SKELETON (gsd_smartcard_service_token_skeleton_new ());
+
+        g_dbus_object_skeleton_add_interface (object, interface);
+        g_object_unref (interface);
+
+        driver = PK11_GetModule (operation->card_slot);
+        driver_object_path = get_object_path_for_driver (self, driver);
+
+        token_name = PK11_GetTokenName (operation->card_slot);
+
+        g_object_set (G_OBJECT (interface),
+                      "driver", driver_object_path,
+                      "name", token_name,
+                      NULL);
+        g_free (driver_object_path);
+
+        g_dbus_object_manager_server_export (self->priv->object_manager_server,
+                                             object);
+
+        G_LOCK (gsd_smartcard_tokens);
+        g_hash_table_insert (priv->tokens, g_strdup (operation->object_path), interface);
+        G_UNLOCK (gsd_smartcard_tokens);
+
+        g_task_return_boolean (task, TRUE);
+
+        return G_SOURCE_REMOVE;
+}
+
+static void
+create_main_thread_source (GSourceFunc   callback,
+                           gpointer      user_data,
+                           GSource     **source_out)
+{
+        GSource *source;
+
+        source = g_idle_source_new ();
+        g_source_set_callback (source, callback, user_data, NULL);
+
+        *source_out = source;
+        g_source_attach (source, NULL);
+        g_source_unref (source);
+}
+
+static void
+register_new_token_in_main_thread (GsdSmartcardService *self,
+                                   PK11SlotInfo        *card_slot,
+                                   char                *object_path,
+                                   GCancellable        *cancellable,
+                                   GAsyncReadyCallback  callback,
+                                   gpointer             user_data)
+{
+        RegisterNewTokenOperation *operation;
+        GTask *task;
+
+        operation = g_new0 (RegisterNewTokenOperation, 1);
+        operation->card_slot = PK11_ReferenceSlot (card_slot);
+        operation->object_path = g_strdup (object_path);
+
+        task = g_task_new (self, cancellable, callback, user_data);
+
+        g_task_set_task_data (task,
+                              operation,
+                              (GDestroyNotify)
+                              destroy_register_new_token_operation);
+
+        create_main_thread_source ((GSourceFunc)
+                                   on_main_thread_to_register_new_token,
+                                   task,
+                                   &operation->main_thread_source);
+}
+
+static gboolean
+register_new_token_in_main_thread_finish (GsdSmartcardService  *self,
+                           GAsyncResult         *result,
+                           GError              **error)
+{
+
+        g_return_val_if_fail (g_task_is_valid (result, G_OBJECT (self)), FALSE);
+
+        return gsd_finish_boolean_task (G_OBJECT (self), result, error);
+}
+
+static void
+on_token_registered (GsdSmartcardService *self,
+                     GAsyncResult        *result,
+                     PK11SlotInfo        *card_slot)
+{
+        gboolean registered;
+        GError *error = NULL;
+
+        registered = register_new_token_in_main_thread_finish (self, result, &error);
+
+        if (!registered) {
+                g_debug ("Couldn't register token: %s",
+                         error->message);
+                goto out;
+        }
+
+        synchronize_token_now (self, card_slot);
+
+out:
+        PK11_FreeSlot (card_slot);
+}
+
+typedef struct
+{
+        PK11SlotInfo *card_slot;
+        GSource      *main_thread_source;
+} SynchronizeTokenOperation;
+
+static void
+destroy_synchronize_token_operation (SynchronizeTokenOperation *operation)
+{
+        g_clear_pointer (&operation->main_thread_source,
+                         (GDestroyNotify)
+                         g_source_destroy);
+        PK11_FreeSlot (operation->card_slot);
+        g_free (operation);
+}
+
+static gboolean
+on_main_thread_to_synchronize_token (GTask *task)
+{
+        GsdSmartcardService *self;
+        SynchronizeTokenOperation *operation;
+
+        self = g_task_get_source_object (task);
+
+        operation = g_task_get_task_data (task);
+        operation->main_thread_source = NULL;
+
+        synchronize_token_now (self, operation->card_slot);
+
+        g_task_return_boolean (task, TRUE);
+
+        return G_SOURCE_REMOVE;
+}
+
+static gboolean
+synchronize_token_in_main_thread_finish (GsdSmartcardService  *self,
+                                         GAsyncResult         *result,
+                                         GError              **error)
+{
+
+        g_return_val_if_fail (g_task_is_valid (result, G_OBJECT (self)), FALSE);
+
+        return gsd_finish_boolean_task (G_OBJECT (self), result, error);
+}
+
+static void
+synchronize_token_in_main_thread (GsdSmartcardService *self,
+                                  PK11SlotInfo        *card_slot,
+                                  GCancellable        *cancellable,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             user_data)
+{
+        SynchronizeTokenOperation *operation;
+        GTask *task;
+
+        operation = g_new0 (SynchronizeTokenOperation, 1);
+        operation->card_slot = PK11_ReferenceSlot (card_slot);
+
+        task = g_task_new (self, cancellable, callback, user_data);
+
+        g_task_set_task_data (task,
+                              operation,
+                              (GDestroyNotify)
+                              destroy_synchronize_token_operation);
+
+        create_main_thread_source ((GSourceFunc)
+                                   on_main_thread_to_synchronize_token,
+                                   task,
+                                   &operation->main_thread_source);
+}
+
+static void
+on_token_synchronized (GsdSmartcardService *self,
+                       GAsyncResult        *result,
+                       PK11SlotInfo        *card_slot)
+{
+        gboolean synchronized;
+        GError *error = NULL;
+
+        synchronized = synchronize_token_in_main_thread_finish (self, result, &error);
+
+        if (!synchronized) {
+                g_debug ("Couldn't synchronize token: %s",
+                         error->message);
+                goto out;
+        }
+
+out:
+        PK11_FreeSlot (card_slot);
+}
+
+void
+gsd_smartcard_service_sync_token (GsdSmartcardService *self,
+                                  PK11SlotInfo        *card_slot,
+                                  GCancellable        *cancellable)
+{
+        GsdSmartcardServicePrivate *priv = self->priv;
+        char *object_path;
+        GDBusInterfaceSkeleton *interface;
+
+        object_path = get_object_path_for_token (self, card_slot);
+
+        G_LOCK (gsd_smartcard_tokens);
+        interface = g_hash_table_lookup (priv->tokens, object_path);
+        G_UNLOCK (gsd_smartcard_tokens);
+
+        if (interface == NULL)
+                register_new_token_in_main_thread (self,
+                                                   card_slot,
+                                                   object_path,
+                                                   cancellable,
+                                                   (GAsyncReadyCallback)
+                                                   on_token_registered,
+                                                   PK11_ReferenceSlot (card_slot));
+
+        else
+                synchronize_token_in_main_thread (self,
+                                                  card_slot,
+                                                  cancellable,
+                                                  (GAsyncReadyCallback)
+                                                  on_token_synchronized,
+                                                  PK11_ReferenceSlot (card_slot));
+
+        g_free (object_path);
+}
diff --git a/plugins/smartcard/gsd-smartcard-service.h b/plugins/smartcard/gsd-smartcard-service.h
new file mode 100644
index 0000000..276c2b2
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-service.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Authors: Ray Strode
+ */
+
+#ifndef __GSD_SMARTCARD_SERVICE_H__
+#define __GSD_SMARTCARD_SERVICE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+#include "gsd-smartcard-manager.h"
+
+#include "org.gnome.Smartcard.h"
+
+#include <prerror.h>
+#include <prinit.h>
+#include <nss.h>
+#include <pk11func.h>
+#include <secmod.h>
+#include <secerr.h>
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_SMARTCARD_SERVICE (gsd_smartcard_service_get_type ())
+#define GSD_SMARTCARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GSD_TYPE_SMARTCARD_SERVICE, 
GsdSmartcardService))
+#define GSD_SMARTCARD_SERVICE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GSD_TYPE_SMARTCARD_SERVICE, 
GsdSmartcardServiceClass))
+#define GSD_IS_SMARTCARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GSD_TYPE_SMARTCARD_SERVICE))
+#define GSD_IS_SMARTCARD_SERVICE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GSD_TYPE_SMARTCARD_SERVICE))
+#define GSD_SMARTCARD_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSD_TYPE_SMARTCARD_SERVICE, 
GsdSmartcardServiceClass))
+
+typedef struct _GsdSmartcardService GsdSmartcardService;
+typedef struct _GsdSmartcardServiceClass GsdSmartcardServiceClass;
+typedef struct _GsdSmartcardServicePrivate GsdSmartcardServicePrivate;
+
+struct _GsdSmartcardService
+{
+        GsdSmartcardServiceManagerSkeleton parent_instance;
+        GsdSmartcardServicePrivate *priv;
+};
+
+struct _GsdSmartcardServiceClass
+{
+        GsdSmartcardServiceManagerSkeletonClass parent_class;
+};
+
+GType gsd_smartcard_service_get_type (void);
+void  gsd_smartcard_service_new_async (GsdSmartcardManager  *manager,
+                                       GCancellable         *cancellable,
+                                       GAsyncReadyCallback   callback,
+                                       gpointer              user_data);
+GsdSmartcardService *gsd_smartcard_service_new_finish (GAsyncResult         *result,
+                                                       GError              **error);
+
+void  gsd_smartcard_service_register_driver (GsdSmartcardService  *service,
+                                             SECMODModule         *driver);
+void  gsd_smartcard_service_sync_token (GsdSmartcardService  *service,
+                                        PK11SlotInfo         *slot_info,
+                                        GCancellable         *cancellable);
+
+
+G_END_DECLS
+
+#endif /* __GSD_SMARTCARD_SERVICE_H__ */
diff --git a/plugins/smartcard/gsd-smartcard-utils.c b/plugins/smartcard/gsd-smartcard-utils.c
new file mode 100644
index 0000000..f160f2b
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-utils.c
@@ -0,0 +1,199 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ * Copyright (C) 2010,2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 "gsd-smartcard-utils.h"
+
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+static char *
+dashed_string_to_studly_caps (const char *dashed_string)
+{
+        char *studly_string;;
+        size_t studly_string_length;
+        size_t i;
+
+        i = 0;
+
+        studly_string = g_strdup (dashed_string);
+        studly_string_length = strlen (studly_string);
+
+        studly_string[i] = g_ascii_toupper (studly_string[i]);
+        i++;
+
+        while (i < studly_string_length) {
+                if (studly_string[i] == '-' || studly_string[i] == '_') {
+                        memmove (studly_string + i,
+                                 studly_string + i + 1,
+                                 studly_string_length - i - 1);
+                        studly_string_length--;
+                        if (g_ascii_isalpha (studly_string[i])) {
+                                studly_string[i] = g_ascii_toupper (studly_string[i]);
+                        }
+                }
+                i++;
+        }
+        studly_string[studly_string_length] = '\0';
+
+        return studly_string;
+}
+
+static char *
+dashed_string_to_dbus_error_string (const char *dashed_string,
+                                    const char *old_prefix,
+                                    const char *new_prefix,
+                                    const char *suffix)
+{
+        char *studly_suffix;
+        char *dbus_error_string;
+        size_t dbus_error_string_length;
+        size_t i;
+
+        i = 0;
+
+        if (g_str_has_prefix (dashed_string, old_prefix) &&
+            (dashed_string[strlen(old_prefix)] == '-' ||
+             dashed_string[strlen(old_prefix)] == '_')) {
+                dashed_string += strlen (old_prefix) + 1;
+        }
+
+        studly_suffix = dashed_string_to_studly_caps (suffix);
+        dbus_error_string = g_strdup_printf ("%s.%s.%s", new_prefix, dashed_string, studly_suffix);
+        g_free (studly_suffix);
+        i += strlen (new_prefix) + 1;
+
+        dbus_error_string_length = strlen (dbus_error_string);
+
+        dbus_error_string[i] = g_ascii_toupper (dbus_error_string[i]);
+        i++;
+
+        while (i < dbus_error_string_length) {
+                if (dbus_error_string[i] == '_' || dbus_error_string[i] == '-') {
+                        dbus_error_string[i] = '.';
+
+                        if (g_ascii_isalpha (dbus_error_string[i + 1])) {
+                                dbus_error_string[i + 1] = g_ascii_toupper (dbus_error_string[i + 1]);
+                        }
+                }
+
+                i++;
+        }
+
+        return dbus_error_string;
+}
+
+/* FIXME: Either move this some central location where all plugins can
+ * access it, or drop it for something more specific.
+ */
+void
+gsd_dbus_register_error_domain (GQuark error_domain,
+                                GType  error_enum)
+{
+        const char *error_domain_string;
+        char *type_name;
+        GType type;
+        GTypeClass *type_class;
+        GEnumClass *enum_class;
+        guint i;
+
+        error_domain_string = g_quark_to_string (error_domain);
+        type_name = dashed_string_to_studly_caps (error_domain_string);
+        type = g_type_from_name (type_name);
+        type_class = g_type_class_ref (type);
+        enum_class = G_ENUM_CLASS (type_class);
+
+        for (i = 0; i < enum_class->n_values; i++) {
+                char *dbus_error_string;
+
+                dbus_error_string = dashed_string_to_dbus_error_string (error_domain_string,
+                                                                        "gsd",
+                                                                        "org.gnome.SettingsDaemon",
+                                                                        enum_class->values[i].value_nick);
+
+                g_debug ("%s: Registering dbus error %s", type_name, dbus_error_string);
+                g_dbus_error_register_error (error_domain,
+                                             enum_class->values[i].value,
+                                             dbus_error_string);
+                g_free (dbus_error_string);
+        }
+
+        g_type_class_unref (type_class);
+}
+
+char *
+gsd_dbus_escape_object_path (const char *data,
+                             gsize       length)
+{
+  const char *p;
+  char *object_path;
+  GString *string;
+
+  g_return_val_if_fail (data != NULL, NULL);
+
+  string = g_string_sized_new ((length + 1) * 6);
+
+  for (p = data; *p != '\0'; p++)
+    {
+      guchar character;
+
+      character = (guchar) * p;
+
+      if (((character >= ((guchar) 'a')) &&
+           (character <= ((guchar) 'z'))) ||
+          ((character >= ((guchar) 'A')) &&
+           (character <= ((guchar) 'Z'))) ||
+          ((character >= ((guchar) '0')) && (character <= ((guchar) '9'))))
+        {
+          g_string_append_c (string, (char) character);
+          continue;
+        }
+
+      g_string_append_printf (string, "_%x_", character);
+    }
+
+  object_path = string->str;
+
+  g_string_free (string, FALSE);
+
+  return object_path;
+}
+
+gboolean
+gsd_finish_boolean_task (GObject       *object,
+                         GAsyncResult  *result,
+                         GError       **error)
+{
+        GTask *task;
+        gboolean return_value;
+
+        g_return_val_if_fail (g_task_is_valid (result, object), FALSE);
+
+        task = G_TASK (result);
+
+        return_value = g_task_propagate_boolean (task, error);
+
+        g_object_unref (task);
+
+        return return_value;
+}
diff --git a/plugins/smartcard/gsd-smartcard-utils.h b/plugins/smartcard/gsd-smartcard-utils.h
new file mode 100644
index 0000000..3e249bd
--- /dev/null
+++ b/plugins/smartcard/gsd-smartcard-utils.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 __GSD_SMARTCARD_UTILS_H
+#define __GSD_SMARTCARD_UTILS_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+void gsd_dbus_register_error_domain (GQuark error_domain, GType error_enum);
+char *gsd_dbus_escape_object_path (const char *data, gsize length);
+gboolean gsd_finish_boolean_task (GObject *object, GAsyncResult *result, GError **error);
+G_END_DECLS
+
+#endif /* __GSD_SMARTCARD_MANAGER_H */
diff --git a/plugins/smartcard/org.gnome.Smartcard.xml b/plugins/smartcard/org.gnome.Smartcard.xml
new file mode 100644
index 0000000..0e2465f
--- /dev/null
+++ b/plugins/smartcard/org.gnome.Smartcard.xml
@@ -0,0 +1,93 @@
+<!DOCTYPE node PUBLIC
+"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd";>
+
+<!--
+ Copyright (C) 2013 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Ray Strode <rstrode redhat com>
+-->
+
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd";>
+ <!--
+ org.gnome.Smartcard.Manager:
+
+ An interface used for managing smartcard functionality.
+ -->
+ <interface name="org.gnome.Smartcard.Manager">
+ <method name="GetLoginToken">
+   <arg name="token" type="o" direction="out"/>
+ </method>
+
+ <method name="GetInsertedTokens">
+   <arg name="tokens" type="ao" direction="out"/>
+ </method>
+ </interface>
+
+ <!--
+ org.gnome.Smartcard.Driver:
+
+ The smartcard driver interface.
+ -->
+ <interface name="org.gnome.Smartcard.Driver">
+ <!--
+ Library:
+ Path to PKCS11 module
+ -->
+ <property name="Library" type="s" access="read"/>
+ <!--
+ Description:
+ String describing the PKCS11 module
+ -->
+ <property name="Description" type="s" access="read"/>
+ </interface>
+
+ <!--
+ org.gnome.Smartcard.Token:
+
+ The smartcard interface.
+ -->
+ <interface name="org.gnome.Smartcard.Token">
+
+ <!--
+ Name:
+ Name of the token
+ -->
+ <property name="Name" type="s" access="read"/>
+
+ <!--
+ Driver:
+ Driver handling token
+ -->
+ <property name="Driver" type="o" access="read"/>
+
+ <!--
+ IsInserted:
+ Whether or not the card is inserted
+ -->
+ <property name="IsInserted" type="b" access="read"/>
+
+ <!--
+ UsedToLogin:
+ Whether or not the card was used to log in
+ -->
+ <property name="UsedToLogin" type="b" access="read"/>
+
+ </interface>
+
+</node>
diff --git a/plugins/smartcard/test-smartcard.c b/plugins/smartcard/test-smartcard.c
new file mode 100644
index 0000000..b5ee3d5
--- /dev/null
+++ b/plugins/smartcard/test-smartcard.c
@@ -0,0 +1,7 @@
+#define NEW gsd_smartcard_manager_new
+#define START gsd_smartcard_manager_start
+#define STOP gsd_smartcard_manager_stop
+#define MANAGER GsdSmartcardManager
+#include "gsd-smartcard-manager.h"
+
+#include "test-plugin.h"


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