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.
384 lines
15 KiB
384 lines
15 KiB
From 3aa4de5e6f2b698abf063ddbea5008f5b732aa18 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.17.0 |
|
|
|
|