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

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