You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
385 lines
15 KiB
385 lines
15 KiB
7 years ago
|
From 492b0d048e126b690754cb3cac29eabfa608a9d9 Mon Sep 17 00:00:00 2001
|
||
|
From: Ray Strode <rstrode@redhat.com>
|
||
|
Date: Fri, 9 Feb 2018 16:40:53 -0500
|
||
|
Subject: [PATCH 2/2] smartcard: handle a smartcard getting removed very
|
||
|
shortly after login
|
||
|
|
||
|
Right now we depend on the smartcard used at login time to be inserted,
|
||
|
at least long enough to read some basic stats about it. This
|
||
|
assumption, of course doesn't necessarly need to hold true. A user
|
||
|
could remove the smartcard immediately after login and we would
|
||
|
misreport that the card wasn't used for login at all.
|
||
|
|
||
|
This commit addresses that edge case by creating a login_token
|
||
|
smartcard alias object that's around even if the login token isn't.
|
||
|
Once the login token does show up it gets synchronized with it, so
|
||
|
both object paths refer to the same underlying token.
|
||
|
---
|
||
|
plugins/smartcard/gsd-smartcard-service.c | 82 +++++++++++++++++++++++++++++++
|
||
|
1 file changed, 82 insertions(+)
|
||
|
|
||
|
diff --git a/plugins/smartcard/gsd-smartcard-service.c b/plugins/smartcard/gsd-smartcard-service.c
|
||
|
index 0710334b..6969ff34 100644
|
||
|
--- a/plugins/smartcard/gsd-smartcard-service.c
|
||
|
+++ b/plugins/smartcard/gsd-smartcard-service.c
|
||
|
@@ -11,60 +11,61 @@
|
||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
* Authors: Ray Strode
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#include "gsd-smartcard-service.h"
|
||
|
#include "org.gnome.SettingsDaemon.Smartcard.h"
|
||
|
#include "gsd-smartcard-manager.h"
|
||
|
#include "gsd-smartcard-enum-types.h"
|
||
|
#include "gsd-smartcard-utils.h"
|
||
|
|
||
|
#include <glib/gi18n.h>
|
||
|
#include <glib/gstdio.h>
|
||
|
#include <gio/gio.h>
|
||
|
|
||
|
struct _GsdSmartcardServicePrivate
|
||
|
{
|
||
|
GDBusConnection *bus_connection;
|
||
|
GDBusObjectManagerServer *object_manager_server;
|
||
|
GsdSmartcardManager *smartcard_manager;
|
||
|
GCancellable *cancellable;
|
||
|
GHashTable *tokens;
|
||
|
|
||
|
+ gboolean login_token_bound;
|
||
|
guint name_id;
|
||
|
};
|
||
|
|
||
|
#define GSD_DBUS_NAME "org.gnome.SettingsDaemon"
|
||
|
#define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
|
||
|
#define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon"
|
||
|
|
||
|
#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);
|
||
|
|
||
|
@@ -83,91 +84,139 @@ 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 const char *
|
||
|
+get_login_token_object_path (GsdSmartcardService *self)
|
||
|
+{
|
||
|
+ return GSD_SMARTCARD_MANAGER_TOKENS_DBUS_PATH "/login_token";
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+register_login_token_alias (GsdSmartcardService *self)
|
||
|
+{
|
||
|
+ GsdSmartcardServicePrivate *priv;
|
||
|
+ GDBusObjectSkeleton *object;
|
||
|
+ GDBusInterfaceSkeleton *interface;
|
||
|
+ const char *object_path;
|
||
|
+ const char *token_name;
|
||
|
+
|
||
|
+ token_name = g_getenv ("PKCS11_LOGIN_TOKEN_NAME");
|
||
|
+
|
||
|
+ if (token_name == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ priv = self->priv;
|
||
|
+
|
||
|
+ object_path = get_login_token_object_path (self);
|
||
|
+ object = G_DBUS_OBJECT_SKELETON (gsd_smartcard_service_object_skeleton_new (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);
|
||
|
+
|
||
|
+ g_object_set (G_OBJECT (interface),
|
||
|
+ "name", token_name,
|
||
|
+ "used-to-login", TRUE,
|
||
|
+ "is-inserted", FALSE,
|
||
|
+ NULL);
|
||
|
+
|
||
|
+ 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 (object_path), interface);
|
||
|
+ G_UNLOCK (gsd_smartcard_tokens);
|
||
|
+}
|
||
|
+
|
||
|
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);
|
||
|
+
|
||
|
+ /* In case the login token is removed at start up, register an
|
||
|
+ * an alias interface that's always around
|
||
|
+ */
|
||
|
+ register_login_token_alias (self);
|
||
|
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);
|
||
|
@@ -191,60 +240,75 @@ get_object_path_for_token (GsdSmartcardService *self,
|
||
|
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_smartcard_utils_escape_object_path (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);
|
||
|
g_free (escaped_library_path);
|
||
|
|
||
|
return object_path;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
gsd_smartcard_service_handle_get_login_token (GsdSmartcardServiceManager *manager,
|
||
|
GDBusMethodInvocation *invocation)
|
||
|
{
|
||
|
GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (manager);
|
||
|
GsdSmartcardServicePrivate *priv = self->priv;
|
||
|
PK11SlotInfo *card_slot;
|
||
|
char *object_path;
|
||
|
|
||
|
card_slot = gsd_smartcard_manager_get_login_token (priv->smartcard_manager);
|
||
|
|
||
|
if (card_slot == NULL) {
|
||
|
+ const char *login_token_object_path;
|
||
|
+
|
||
|
+ /* If we know there's a login token but it was removed before the
|
||
|
+ * smartcard manager could examine it, just return the generic login
|
||
|
+ * token object path
|
||
|
+ */
|
||
|
+ login_token_object_path = get_login_token_object_path (self);
|
||
|
+
|
||
|
+ if (g_hash_table_contains (priv->tokens, login_token_object_path)) {
|
||
|
+ gsd_smartcard_service_manager_complete_get_login_token (manager,
|
||
|
+ invocation,
|
||
|
+ login_token_object_path);
|
||
|
+ return TRUE;
|
||
|
+ }
|
||
|
+
|
||
|
g_dbus_method_invocation_return_error (invocation,
|
||
|
GSD_SMARTCARD_MANAGER_ERROR,
|
||
|
GSD_SMARTCARD_MANAGER_ERROR_FINDING_SMARTCARD,
|
||
|
_("User was not logged in with smartcard."));
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
object_path = get_object_path_for_token (self, card_slot);
|
||
|
gsd_smartcard_service_manager_complete_get_login_token (manager,
|
||
|
invocation,
|
||
|
object_path);
|
||
|
g_free (object_path);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
gsd_smartcard_service_handle_get_inserted_tokens (GsdSmartcardServiceManager *manager,
|
||
|
GDBusMethodInvocation *invocation)
|
||
|
{
|
||
|
GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (manager);
|
||
|
GsdSmartcardServicePrivate *priv = self->priv;
|
||
|
GList *inserted_tokens, *node;
|
||
|
GPtrArray *object_paths;
|
||
|
|
||
|
inserted_tokens = gsd_smartcard_manager_get_inserted_tokens (priv->smartcard_manager,
|
||
|
NULL);
|
||
|
|
||
|
object_paths = g_ptr_array_new ();
|
||
|
@@ -498,60 +562,78 @@ synchronize_token_now (GsdSmartcardService *self,
|
||
|
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");
|
||
|
|
||
|
if (!is_present && is_login_card) {
|
||
|
gboolean was_present;
|
||
|
|
||
|
g_object_get (G_OBJECT (interface),
|
||
|
"is-inserted", &was_present,
|
||
|
NULL);
|
||
|
|
||
|
if (was_present)
|
||
|
gsd_smartcard_manager_do_remove_action (priv->smartcard_manager);
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
|
||
|
+ if (is_login_card && !priv->login_token_bound) {
|
||
|
+ const char *login_token_path;
|
||
|
+ GDBusInterfaceSkeleton *login_token_interface;
|
||
|
+
|
||
|
+ login_token_path = get_login_token_object_path (self);
|
||
|
+ login_token_interface = g_hash_table_lookup (priv->tokens, login_token_path);
|
||
|
+
|
||
|
+ if (login_token_interface != NULL) {
|
||
|
+ g_object_bind_property (interface, "driver",
|
||
|
+ login_token_interface, "driver",
|
||
|
+ G_BINDING_SYNC_CREATE);
|
||
|
+ g_object_bind_property (interface, "is-inserted",
|
||
|
+ login_token_interface, "is-inserted",
|
||
|
+ G_BINDING_SYNC_CREATE);
|
||
|
+ priv->login_token_bound = TRUE;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
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;
|
||
|
--
|
||
|
2.14.3
|
||
|
|