Blame SOURCES/0002-smartcard-handle-a-smartcard-getting-removed-very-sh.patch

27be76
From 3aa4de5e6f2b698abf063ddbea5008f5b732aa18 Mon Sep 17 00:00:00 2001
7faf05
From: Ray Strode <rstrode@redhat.com>
7faf05
Date: Fri, 9 Feb 2018 16:40:53 -0500
7faf05
Subject: [PATCH 2/2] smartcard: handle a smartcard getting removed very
7faf05
 shortly after login
7faf05
7faf05
Right now we depend on the smartcard used at login time to be inserted,
7faf05
at least long enough to read some basic stats about it.  This
7faf05
assumption, of course doesn't necessarly need to hold true.  A user
7faf05
could remove the smartcard immediately after login and we would
7faf05
misreport that the card wasn't used for login at all.
7faf05
7faf05
This commit addresses that edge case by creating a login_token
7faf05
smartcard alias object that's around even if the login token isn't.
7faf05
Once the login token does show up it gets synchronized with it, so
7faf05
both object paths refer to the same underlying token.
7faf05
---
27be76
 plugins/smartcard/gsd-smartcard-service.c | 82 +++++++++++++++++++++++
7faf05
 1 file changed, 82 insertions(+)
7faf05
7faf05
diff --git a/plugins/smartcard/gsd-smartcard-service.c b/plugins/smartcard/gsd-smartcard-service.c
7faf05
index 0710334b..6969ff34 100644
7faf05
--- a/plugins/smartcard/gsd-smartcard-service.c
7faf05
+++ b/plugins/smartcard/gsd-smartcard-service.c
7faf05
@@ -11,60 +11,61 @@
7faf05
  * WITHOUT ANY WARRANTY; without even the implied warranty of
7faf05
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7faf05
  * General Public License for more details.
7faf05
  *
7faf05
  * You should have received a copy of the GNU General Public License
7faf05
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
7faf05
  *
7faf05
  * Authors: Ray Strode
7faf05
  */
7faf05
 
7faf05
 #include "config.h"
7faf05
 
7faf05
 #include "gsd-smartcard-service.h"
7faf05
 #include "org.gnome.SettingsDaemon.Smartcard.h"
7faf05
 #include "gsd-smartcard-manager.h"
7faf05
 #include "gsd-smartcard-enum-types.h"
7faf05
 #include "gsd-smartcard-utils.h"
7faf05
 
7faf05
 #include <glib/gi18n.h>
7faf05
 #include <glib/gstdio.h>
7faf05
 #include <gio/gio.h>
7faf05
 
7faf05
 struct _GsdSmartcardServicePrivate
7faf05
 {
7faf05
         GDBusConnection            *bus_connection;
7faf05
         GDBusObjectManagerServer   *object_manager_server;
7faf05
         GsdSmartcardManager        *smartcard_manager;
7faf05
         GCancellable               *cancellable;
7faf05
         GHashTable                 *tokens;
7faf05
 
7faf05
+        gboolean                    login_token_bound;
7faf05
         guint name_id;
7faf05
 };
7faf05
 
7faf05
 #define GSD_DBUS_NAME "org.gnome.SettingsDaemon"
7faf05
 #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
7faf05
 #define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon"
7faf05
 
7faf05
 #define GSD_SMARTCARD_DBUS_NAME GSD_DBUS_NAME ".Smartcard"
7faf05
 #define GSD_SMARTCARD_DBUS_PATH GSD_DBUS_PATH "/Smartcard"
7faf05
 #define GSD_SMARTCARD_MANAGER_DBUS_PATH GSD_SMARTCARD_DBUS_PATH "/Manager"
7faf05
 #define GSD_SMARTCARD_MANAGER_DRIVERS_DBUS_PATH GSD_SMARTCARD_MANAGER_DBUS_PATH "/Drivers"
7faf05
 #define GSD_SMARTCARD_MANAGER_TOKENS_DBUS_PATH  GSD_SMARTCARD_MANAGER_DBUS_PATH "/Tokens"
7faf05
 
7faf05
 enum {
7faf05
         PROP_0,
7faf05
         PROP_MANAGER,
7faf05
         PROP_BUS_CONNECTION
7faf05
 };
7faf05
 
7faf05
 static void gsd_smartcard_service_set_property (GObject *object,
7faf05
                                                 guint property_id,
7faf05
                                                 const GValue *value,
7faf05
                                                 GParamSpec *param_spec);
7faf05
 static void gsd_smartcard_service_get_property (GObject *object,
7faf05
                                                 guint property_id,
7faf05
                                                 GValue *value,
7faf05
                                                 GParamSpec *param_spec);
7faf05
 static void async_initable_interface_init (GAsyncInitableIface *interface);
7faf05
 static void smartcard_service_manager_interface_init (GsdSmartcardServiceManagerIface *interface);
7faf05
 
7faf05
@@ -83,91 +84,139 @@ set_bus_connection (GsdSmartcardService  *self,
7faf05
                     GDBusConnection      *connection)
7faf05
 {
7faf05
         GsdSmartcardServicePrivate *priv = self->priv;
7faf05
 
7faf05
         if (priv->bus_connection != connection) {
7faf05
                 g_clear_object (&priv->bus_connection);
7faf05
                 priv->bus_connection = g_object_ref (connection);
7faf05
                 g_object_notify (G_OBJECT (self), "bus-connection");
7faf05
         }
7faf05
 }
7faf05
 
7faf05
 static void
7faf05
 register_object_manager (GsdSmartcardService *self)
7faf05
 {
7faf05
         GsdSmartcardServiceObjectSkeleton *object;
7faf05
 
7faf05
         self->priv->object_manager_server = g_dbus_object_manager_server_new (GSD_SMARTCARD_DBUS_PATH);
7faf05
 
7faf05
         object = gsd_smartcard_service_object_skeleton_new (GSD_SMARTCARD_MANAGER_DBUS_PATH);
7faf05
         gsd_smartcard_service_object_skeleton_set_manager (object,
7faf05
                                                            GSD_SMARTCARD_SERVICE_MANAGER (self));
7faf05
 
7faf05
         g_dbus_object_manager_server_export (self->priv->object_manager_server,
7faf05
                                              G_DBUS_OBJECT_SKELETON (object));
7faf05
         g_object_unref (object);
7faf05
 
7faf05
         g_dbus_object_manager_server_set_connection (self->priv->object_manager_server,
7faf05
                                                      self->priv->bus_connection);
7faf05
 }
7faf05
 
7faf05
+static const char *
7faf05
+get_login_token_object_path (GsdSmartcardService *self)
7faf05
+{
7faf05
+        return GSD_SMARTCARD_MANAGER_TOKENS_DBUS_PATH "/login_token";
7faf05
+}
7faf05
+
7faf05
+static void
7faf05
+register_login_token_alias (GsdSmartcardService *self)
7faf05
+{
7faf05
+        GsdSmartcardServicePrivate *priv;
7faf05
+        GDBusObjectSkeleton *object;
7faf05
+        GDBusInterfaceSkeleton *interface;
7faf05
+        const char *object_path;
7faf05
+        const char *token_name;
7faf05
+
7faf05
+        token_name = g_getenv ("PKCS11_LOGIN_TOKEN_NAME");
7faf05
+
7faf05
+        if (token_name == NULL)
7faf05
+                return;
7faf05
+
7faf05
+        priv = self->priv;
7faf05
+
7faf05
+        object_path = get_login_token_object_path (self);
7faf05
+        object = G_DBUS_OBJECT_SKELETON (gsd_smartcard_service_object_skeleton_new (object_path));
7faf05
+        interface = G_DBUS_INTERFACE_SKELETON (gsd_smartcard_service_token_skeleton_new ());
7faf05
+
7faf05
+        g_dbus_object_skeleton_add_interface (object, interface);
7faf05
+        g_object_unref (interface);
7faf05
+
7faf05
+        g_object_set (G_OBJECT (interface),
7faf05
+                      "name", token_name,
7faf05
+                      "used-to-login", TRUE,
7faf05
+                      "is-inserted", FALSE,
7faf05
+                      NULL);
7faf05
+
7faf05
+        g_dbus_object_manager_server_export (self->priv->object_manager_server,
7faf05
+                                             object);
7faf05
+
7faf05
+        G_LOCK (gsd_smartcard_tokens);
7faf05
+        g_hash_table_insert (priv->tokens, g_strdup (object_path), interface);
7faf05
+        G_UNLOCK (gsd_smartcard_tokens);
7faf05
+}
7faf05
+
7faf05
 static void
7faf05
 on_bus_gotten (GObject      *source_object,
7faf05
                GAsyncResult *result,
7faf05
                GTask        *task)
7faf05
 {
7faf05
         GsdSmartcardService *self;
7faf05
         GsdSmartcardServicePrivate *priv;
7faf05
         GDBusConnection *connection;
7faf05
         GError *error = NULL;
7faf05
 
7faf05
         connection = g_bus_get_finish (result, &error);
7faf05
         if (connection == NULL) {
7faf05
                 g_task_return_error (task, error);
7faf05
                 goto out;
7faf05
         }
7faf05
 
7faf05
         g_debug ("taking name %s on session bus", GSD_SMARTCARD_DBUS_NAME);
7faf05
 
7faf05
         self = g_task_get_source_object (task);
7faf05
         priv = self->priv;
7faf05
 
7faf05
         set_bus_connection (self, connection);
7faf05
 
7faf05
         register_object_manager (self);
7faf05
         priv->name_id = g_bus_own_name_on_connection (connection,
7faf05
                                                       GSD_SMARTCARD_DBUS_NAME,
7faf05
                                                       G_BUS_NAME_OWNER_FLAGS_NONE,
7faf05
                                                       NULL,
7faf05
                                                       NULL,
7faf05
                                                       NULL,
7faf05
                                                       NULL);
7faf05
+
7faf05
+        /* In case the login token is removed at start up, register an
7faf05
+         * an alias interface that's always around
7faf05
+         */
7faf05
+        register_login_token_alias (self);
7faf05
         g_task_return_boolean (task, TRUE);
7faf05
 
7faf05
 out:
7faf05
         g_object_unref (task);
7faf05
         return;
7faf05
 }
7faf05
 
7faf05
 static gboolean
7faf05
 gsd_smartcard_service_initable_init_finish (GAsyncInitable  *initable,
7faf05
                                             GAsyncResult    *result,
7faf05
                                             GError         **error)
7faf05
 {
7faf05
         GTask *task;
7faf05
 
7faf05
         task = G_TASK (result);
7faf05
 
7faf05
         return g_task_propagate_boolean (task, error);
7faf05
 }
7faf05
 
7faf05
 static void
7faf05
 gsd_smartcard_service_initable_init_async (GAsyncInitable      *initable,
7faf05
                                            int                  io_priority,
7faf05
                                            GCancellable        *cancellable,
7faf05
                                            GAsyncReadyCallback  callback,
7faf05
                                            gpointer             user_data)
7faf05
 {
7faf05
         GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (initable);
7faf05
         GTask *task;
7faf05
 
7faf05
         task = g_task_new (G_OBJECT (self), cancellable, callback, user_data);
7faf05
@@ -191,60 +240,75 @@ get_object_path_for_token (GsdSmartcardService *self,
7faf05
         char *escaped_library_path;
7faf05
         SECMODModule *driver;
7faf05
         CK_SLOT_ID slot_id;
7faf05
 
7faf05
         driver = PK11_GetModule (card_slot);
7faf05
         slot_id = PK11_GetSlotID (card_slot);
7faf05
 
7faf05
         escaped_library_path = gsd_smartcard_utils_escape_object_path (driver->dllName);
7faf05
 
7faf05
         object_path = g_strdup_printf ("%s/token_from_%s_slot_%lu",
7faf05
                                        GSD_SMARTCARD_MANAGER_TOKENS_DBUS_PATH,
7faf05
                                        escaped_library_path,
7faf05
                                        (gulong) slot_id);
7faf05
         g_free (escaped_library_path);
7faf05
 
7faf05
         return object_path;
7faf05
 }
7faf05
 
7faf05
 static gboolean
7faf05
 gsd_smartcard_service_handle_get_login_token (GsdSmartcardServiceManager *manager,
7faf05
                                               GDBusMethodInvocation      *invocation)
7faf05
 {
7faf05
         GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (manager);
7faf05
         GsdSmartcardServicePrivate *priv = self->priv;
7faf05
         PK11SlotInfo *card_slot;
7faf05
         char *object_path;
7faf05
 
7faf05
         card_slot = gsd_smartcard_manager_get_login_token (priv->smartcard_manager);
7faf05
 
7faf05
         if (card_slot == NULL) {
7faf05
+                const char *login_token_object_path;
7faf05
+
7faf05
+                /* If we know there's a login token but it was removed before the
7faf05
+                 * smartcard manager could examine it, just return the generic login
7faf05
+                 * token object path
7faf05
+                 */
7faf05
+                login_token_object_path = get_login_token_object_path (self);
7faf05
+
7faf05
+                if (g_hash_table_contains (priv->tokens, login_token_object_path)) {
7faf05
+                        gsd_smartcard_service_manager_complete_get_login_token (manager,
7faf05
+                                                                                invocation,
7faf05
+                                                                                login_token_object_path);
7faf05
+                        return TRUE;
7faf05
+                }
7faf05
+
7faf05
                 g_dbus_method_invocation_return_error (invocation,
7faf05
                                                        GSD_SMARTCARD_MANAGER_ERROR,
7faf05
                                                        GSD_SMARTCARD_MANAGER_ERROR_FINDING_SMARTCARD,
7faf05
                                                        _("User was not logged in with smartcard."));
7faf05
 
7faf05
                 return TRUE;
7faf05
         }
7faf05
 
7faf05
         object_path = get_object_path_for_token (self, card_slot);
7faf05
         gsd_smartcard_service_manager_complete_get_login_token (manager,
7faf05
                                                                 invocation,
7faf05
                                                                 object_path);
7faf05
         g_free (object_path);
7faf05
 
7faf05
         return TRUE;
7faf05
 }
7faf05
 
7faf05
 static gboolean
7faf05
 gsd_smartcard_service_handle_get_inserted_tokens (GsdSmartcardServiceManager *manager,
7faf05
                                                   GDBusMethodInvocation      *invocation)
7faf05
 {
7faf05
         GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (manager);
7faf05
         GsdSmartcardServicePrivate *priv = self->priv;
7faf05
         GList *inserted_tokens, *node;
7faf05
         GPtrArray *object_paths;
7faf05
 
7faf05
         inserted_tokens = gsd_smartcard_manager_get_inserted_tokens (priv->smartcard_manager,
7faf05
                                                                      NULL);
7faf05
 
7faf05
         object_paths = g_ptr_array_new ();
7faf05
@@ -498,60 +562,78 @@ synchronize_token_now (GsdSmartcardService *self,
7faf05
                 is_login_card = TRUE;
7faf05
         else
7faf05
                 is_login_card = FALSE;
7faf05
 
7faf05
         g_debug ("===============================");
7faf05
         g_debug (" Token '%s'", token_name);
7faf05
         g_debug (" Inserted: %s", is_present? "yes" : "no");
7faf05
         g_debug (" Previously used to login: %s", is_login_card? "yes" : "no");
7faf05
         g_debug ("===============================\n");
7faf05
 
7faf05
         if (!is_present && is_login_card) {
7faf05
                 gboolean was_present;
7faf05
 
7faf05
                 g_object_get (G_OBJECT (interface),
7faf05
                               "is-inserted", &was_present,
7faf05
                               NULL);
7faf05
 
7faf05
                 if (was_present)
7faf05
                         gsd_smartcard_manager_do_remove_action (priv->smartcard_manager);
7faf05
         }
7faf05
 
7faf05
         g_object_set (G_OBJECT (interface),
7faf05
                       "used-to-login", is_login_card,
7faf05
                       "is-inserted", is_present,
7faf05
                       NULL);
7faf05
         g_object_get (G_OBJECT (interface),
7faf05
                       "used-to-login", &is_login_card,
7faf05
                       "is-inserted", &is_present,
7faf05
                       NULL);
7faf05
 
7faf05
+        if (is_login_card && !priv->login_token_bound) {
7faf05
+                const char *login_token_path;
7faf05
+                GDBusInterfaceSkeleton *login_token_interface;
7faf05
+
7faf05
+                login_token_path = get_login_token_object_path (self);
7faf05
+                login_token_interface = g_hash_table_lookup (priv->tokens, login_token_path);
7faf05
+
7faf05
+                if (login_token_interface != NULL) {
7faf05
+                        g_object_bind_property (interface, "driver",
7faf05
+                                                login_token_interface, "driver",
7faf05
+                                                G_BINDING_SYNC_CREATE);
7faf05
+                        g_object_bind_property (interface, "is-inserted",
7faf05
+                                                login_token_interface, "is-inserted",
7faf05
+                                                G_BINDING_SYNC_CREATE);
7faf05
+                        priv->login_token_bound = TRUE;
7faf05
+                }
7faf05
+        }
7faf05
+
7faf05
 out:
7faf05
         G_UNLOCK (gsd_smartcard_tokens);
7faf05
 }
7faf05
 
7faf05
 typedef struct
7faf05
 {
7faf05
         PK11SlotInfo *card_slot;
7faf05
         char         *object_path;
7faf05
         GSource      *main_thread_source;
7faf05
 } RegisterNewTokenOperation;
7faf05
 
7faf05
 static void
7faf05
 destroy_register_new_token_operation (RegisterNewTokenOperation *operation)
7faf05
 {
7faf05
         g_clear_pointer (&operation->main_thread_source,
7faf05
                          (GDestroyNotify) g_source_destroy);
7faf05
         PK11_FreeSlot (operation->card_slot);
7faf05
         g_free (operation->object_path);
7faf05
         g_free (operation);
7faf05
 }
7faf05
 
7faf05
 static gboolean
7faf05
 on_main_thread_to_register_new_token (GTask *task)
7faf05
 {
7faf05
         GsdSmartcardService *self;
7faf05
         GsdSmartcardServicePrivate *priv;
7faf05
         GDBusObjectSkeleton *object;
7faf05
         GDBusInterfaceSkeleton *interface;
7faf05
         RegisterNewTokenOperation *operation;
7faf05
         SECMODModule *driver;
7faf05
-- 
27be76
2.17.0
7faf05