Blame SOURCES/0015-libgdm-Don-t-leak-user-verifier-extensions-on-unlock.patch

52125b
From 1b212d79948db72a302234ba1d23d267375be47b Mon Sep 17 00:00:00 2001
b61949
From: Ray Strode <rstrode@redhat.com>
b61949
Date: Fri, 25 Sep 2020 15:27:47 -0400
b61949
Subject: [PATCH 15/15] libgdm: Don't leak user verifier extensions on unlock
b61949
b61949
GdmClient fails to free the hash table associated with user
b61949
verifier extensions when the client is done with the user verifier.
b61949
b61949
This commit ties the user verifier extensions to the user verifier
b61949
instance associated with it, instead of storing the extensions
b61949
directly in the client struct.
b61949
---
52125b
 libgdm/gdm-client.c | 165 +++++++++++++++++++++++++++++++++++---------
52125b
 1 file changed, 131 insertions(+), 34 deletions(-)
b61949
b61949
diff --git a/libgdm/gdm-client.c b/libgdm/gdm-client.c
52125b
index afe78087f..7074cb14b 100644
b61949
--- a/libgdm/gdm-client.c
b61949
+++ b/libgdm/gdm-client.c
52125b
@@ -14,60 +14,61 @@
52125b
  * GNU General Public License for more details.
52125b
  *
52125b
  * You should have received a copy of the GNU General Public License
52125b
  * along with this program; if not, write to the Free Software
52125b
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
52125b
  *
52125b
  */
52125b
 
52125b
 #include "config.h"
52125b
 
52125b
 #include <stdlib.h>
52125b
 #include <stdio.h>
52125b
 #include <unistd.h>
52125b
 #include <string.h>
52125b
 
52125b
 #include <glib.h>
52125b
 #include <glib/gi18n.h>
52125b
 #include <glib-object.h>
52125b
 
52125b
 #include "gdm-client.h"
52125b
 #include "gdm-client-glue.h"
52125b
 #include "gdm-manager-glue.h"
52125b
 
52125b
 #define GDM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CLIENT, GdmClientPrivate))
52125b
 
52125b
 #define SESSION_DBUS_PATH      "/org/gnome/DisplayManager/Session"
52125b
 
52125b
 struct GdmClientPrivate
52125b
 {
52125b
         GdmUserVerifier    *user_verifier;
52125b
+        GdmUserVerifier    *user_verifier_for_reauth;
52125b
         GHashTable         *user_verifier_extensions;
52125b
 
52125b
         GdmGreeter         *greeter;
52125b
         GdmRemoteGreeter   *remote_greeter;
52125b
         GdmChooser         *chooser;
52125b
 
52125b
         char              **enabled_extensions;
52125b
 };
52125b
 
52125b
 static void     gdm_client_class_init  (GdmClientClass *klass);
52125b
 static void     gdm_client_init        (GdmClient      *client);
52125b
 static void     gdm_client_finalize    (GObject        *object);
52125b
 
52125b
 G_DEFINE_TYPE (GdmClient, gdm_client, G_TYPE_OBJECT);
52125b
 
52125b
 static gpointer client_object = NULL;
52125b
 
52125b
 GQuark
52125b
 gdm_client_error_quark (void)
52125b
 {
52125b
         static GQuark error_quark = 0;
52125b
 
52125b
         if (error_quark == 0)
52125b
                 error_quark = g_quark_from_static_string ("gdm-client");
52125b
 
52125b
         return error_quark;
52125b
 }
52125b
 
52125b
 static GDBusConnection *
52125b
 gdm_client_get_open_connection (GdmClient *client)
52125b
@@ -147,193 +148,204 @@ user_verifier_data_new (GTask *task, GdmUserVerifier *user_verifier)
b61949
 
b61949
         data = g_slice_new (UserVerifierData);
b61949
         data->task = g_object_ref (task);
b61949
         data->user_verifier = g_object_ref (user_verifier);
b61949
 
b61949
         return data;
b61949
 }
b61949
 
b61949
 static void
b61949
 user_verifier_data_free (UserVerifierData *data)
b61949
 {
b61949
         g_object_unref (data->task);
b61949
         g_object_unref (data->user_verifier);
b61949
         g_slice_free (UserVerifierData, data);
b61949
 }
b61949
 
b61949
 static void
b61949
 complete_user_verifier_proxy_operation (GdmClient          *client,
b61949
                                         UserVerifierData   *data)
b61949
 {
b61949
         g_task_return_pointer (data->task,
b61949
                                g_object_ref (data->user_verifier),
b61949
                                (GDestroyNotify) g_object_unref);
b61949
         user_verifier_data_free (data);
b61949
 }
b61949
 
b61949
 static void
b61949
 maybe_complete_user_verifier_proxy_operation (GdmClient          *client,
b61949
                                               UserVerifierData   *data)
b61949
 {
b61949
+        GHashTable *user_verifier_extensions;
b61949
         GHashTableIter iter;
b61949
         gpointer key, value;
b61949
 
b61949
-        if (client->priv->user_verifier_extensions != NULL) {
b61949
-                g_hash_table_iter_init (&iter, client->priv->user_verifier_extensions);
52125b
+        user_verifier_extensions = g_object_get_data (G_OBJECT (data->user_verifier), "gdm-client-user-verifier-extensions");
b61949
+        if (user_verifier_extensions != NULL) {
b61949
+                g_hash_table_iter_init (&iter, user_verifier_extensions);
b61949
                 while (g_hash_table_iter_next (&iter, &key, &value)) {
b61949
                         if (value == NULL)
b61949
                                 return;
b61949
                 }
b61949
         }
b61949
 
b61949
         complete_user_verifier_proxy_operation (client, data);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_user_verifier_choice_list_proxy_created (GObject            *source,
b61949
                                             GAsyncResult       *result,
b61949
                                             UserVerifierData   *data)
b61949
 {
b61949
+        GHashTable *user_verifier_extensions;
b61949
         g_autoptr(GdmClient)       client = NULL;
b61949
         GdmUserVerifierChoiceList *choice_list;
b61949
         g_autoptr(GError)          error = NULL;
b61949
 
b61949
         client = GDM_CLIENT (g_async_result_get_source_object (G_ASYNC_RESULT (data->task)));
b61949
 
b61949
+        user_verifier_extensions = g_object_get_data (G_OBJECT (data->user_verifier), "gdm-client-user-verifier-extensions");
b61949
         choice_list = gdm_user_verifier_choice_list_proxy_new_finish (result, &error);
b61949
 
b61949
         if (choice_list == NULL) {
b61949
                 g_debug ("Couldn't create UserVerifier ChoiceList proxy: %s", error->message);
b61949
-                g_hash_table_remove (client->priv->user_verifier_extensions, gdm_user_verifier_choice_list_interface_info ()->name);
b61949
+                g_hash_table_remove (user_verifier_extensions, gdm_user_verifier_choice_list_interface_info ()->name);
b61949
         } else {
b61949
-                g_hash_table_replace (client->priv->user_verifier_extensions, gdm_user_verifier_choice_list_interface_info ()->name, choice_list);
b61949
+                g_hash_table_replace (user_verifier_extensions, gdm_user_verifier_choice_list_interface_info ()->name, choice_list);
b61949
         }
b61949
 
b61949
         maybe_complete_user_verifier_proxy_operation (client, data);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_user_verifier_extensions_enabled (GdmUserVerifier    *user_verifier,
b61949
                                      GAsyncResult       *result,
b61949
                                      UserVerifierData   *data)
b61949
 {
b61949
         g_autoptr(GdmClient)       client = NULL;
b61949
+        GHashTable *user_verifier_extensions;
b61949
         GCancellable *cancellable;
b61949
         GDBusConnection *connection;
b61949
         g_autoptr(GError) error = NULL;
b61949
         size_t     i;
b61949
 
b61949
         client = GDM_CLIENT (g_async_result_get_source_object (G_ASYNC_RESULT (data->task)));
b61949
         cancellable = g_task_get_cancellable (data->task);
b61949
+        user_verifier_extensions = g_object_get_data (G_OBJECT (user_verifier), "gdm-client-user-verifier-extensions");
b61949
 
b61949
         gdm_user_verifier_call_enable_extensions_finish (user_verifier, result, &error);
b61949
 
b61949
         if (error != NULL) {
b61949
                 g_debug ("Couldn't enable user verifier extensions: %s",
b61949
                          error->message);
b61949
                 complete_user_verifier_proxy_operation (client, data);
b61949
                 return;
b61949
         }
b61949
 
b61949
         connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (user_verifier));
b61949
 
b61949
         for (i = 0; client->priv->enabled_extensions[i] != NULL; i++) {
b61949
                 g_debug ("Enabled extensions[%lu] = %s", i, client->priv->enabled_extensions[i]);
b61949
-                g_hash_table_insert (client->priv->user_verifier_extensions, client->priv->enabled_extensions[i], NULL);
b61949
+                g_hash_table_insert (user_verifier_extensions, client->priv->enabled_extensions[i], NULL);
b61949
 
b61949
                 if (strcmp (client->priv->enabled_extensions[i],
b61949
                             gdm_user_verifier_choice_list_interface_info ()->name) == 0) {
b61949
-                        g_hash_table_insert (client->priv->user_verifier_extensions, client->priv->enabled_extensions[i], NULL);
b61949
+                        g_hash_table_insert (user_verifier_extensions, client->priv->enabled_extensions[i], NULL);
b61949
                         gdm_user_verifier_choice_list_proxy_new (connection,
b61949
                                                                  G_DBUS_PROXY_FLAGS_NONE,
b61949
                                                                  NULL,
b61949
                                                                  SESSION_DBUS_PATH,
b61949
                                                                  cancellable,
b61949
                                                                  (GAsyncReadyCallback)
b61949
                                                                  on_user_verifier_choice_list_proxy_created,
b61949
                                                                  data);
b61949
                 } else {
b61949
                         g_debug ("User verifier extension %s is unsupported", client->priv->enabled_extensions[i]);
b61949
-                        g_hash_table_remove (client->priv->user_verifier_extensions,
b61949
+                        g_hash_table_remove (user_verifier_extensions,
b61949
                                              client->priv->enabled_extensions[i]);
b61949
                 }
b61949
         }
b61949
 
b61949
-        if (g_hash_table_size (client->priv->user_verifier_extensions) == 0) {
b61949
+        if (g_hash_table_size (user_verifier_extensions) == 0) {
b61949
                 g_debug ("No supported user verifier extensions");
b61949
                 complete_user_verifier_proxy_operation (client, data);
b61949
         }
b61949
 
b61949
 }
b61949
 
b61949
 static void
b61949
 free_interface_skeleton (GDBusInterfaceSkeleton *interface)
b61949
 {
b61949
         if (interface == NULL)
b61949
                 return;
b61949
 
b61949
         g_object_unref (interface);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_user_verifier_proxy_created (GObject            *source,
b61949
                                 GAsyncResult       *result,
b61949
                                 gpointer            user_data)
b61949
 {
b61949
         g_autoptr(GdmClient)       self = NULL;
b61949
+        GHashTable         *user_verifier_extensions;
b61949
         GCancellable    *cancellable = NULL;
b61949
         g_autoptr(GdmUserVerifier) user_verifier = NULL;
b61949
         g_autoptr(GTask)           task = user_data;
b61949
         g_autoptr(GError)          error = NULL;
b61949
 
b61949
         user_verifier = gdm_user_verifier_proxy_new_finish (result, &error);
b61949
         if (user_verifier == NULL) {
b61949
                 g_task_return_error (task, g_steal_pointer (&error));
b61949
                 return;
b61949
         }
b61949
 
b61949
         g_debug ("UserVerifier %p created", user_verifier);
b61949
 
b61949
         self = GDM_CLIENT (g_async_result_get_source_object (G_ASYNC_RESULT (task)));
b61949
         if (self->priv->enabled_extensions == NULL) {
b61949
                 g_debug ("no enabled extensions");
b61949
                 g_task_return_pointer (task,
b61949
                                        g_steal_pointer (&user_verifier),
b61949
                                        (GDestroyNotify) g_object_unref);
b61949
                 return;
b61949
         }
b61949
 
b61949
-        self->priv->user_verifier_extensions = g_hash_table_new_full (g_str_hash,
b61949
-                                                                      g_str_equal,
b61949
-                                                                      NULL,
b61949
-                                                                      (GDestroyNotify)
b61949
-                                                                      free_interface_skeleton);
b61949
+        user_verifier_extensions = g_hash_table_new_full (g_str_hash,
b61949
+                                                          g_str_equal,
b61949
+                                                          NULL,
b61949
+                                                          (GDestroyNotify)
b61949
+                                                          free_interface_skeleton);
b61949
+        g_object_set_data_full (G_OBJECT (user_verifier),
b61949
+                                "gdm-client-user-verifier-extensions",
b61949
+                                user_verifier_extensions,
b61949
+                                (GDestroyNotify) g_hash_table_unref);
b61949
         cancellable = g_task_get_cancellable (task);
b61949
         gdm_user_verifier_call_enable_extensions (user_verifier,
b61949
                                                   (const char * const *)
b61949
                                                   self->priv->enabled_extensions,
b61949
                                                   cancellable,
b61949
                                                   (GAsyncReadyCallback)
b61949
                                                   on_user_verifier_extensions_enabled,
b61949
                                                   user_verifier_data_new (task, user_verifier));
b61949
 }
b61949
 
b61949
 static void
b61949
 on_reauthentication_channel_connected (GObject            *source_object,
b61949
                                        GAsyncResult       *result,
b61949
                                        gpointer            user_data)
b61949
 {
b61949
         GCancellable *cancellable;
b61949
         g_autoptr(GTask)           task = user_data;
b61949
         g_autoptr(GDBusConnection) connection = NULL;
b61949
         g_autoptr(GError)          error = NULL;
b61949
 
b61949
         connection = g_dbus_connection_new_for_address_finish (result, &error);
b61949
         if (!connection) {
b61949
                 g_task_return_error (task, g_steal_pointer (&error));
b61949
                 return;
b61949
         }
b61949
 
b61949
         cancellable = g_task_get_cancellable (task);
b61949
         gdm_user_verifier_proxy_new (connection,
b61949
                                      G_DBUS_PROXY_FLAGS_NONE,
b61949
                                      NULL,
52125b
@@ -533,191 +545,229 @@ gdm_client_open_reauthentication_channel_sync (GdmClient     *client,
52125b
 
52125b
         ret = gdm_manager_call_open_reauthentication_channel_sync (manager,
52125b
                                                                    username,
52125b
                                                                    &address,
52125b
                                                                    cancellable,
52125b
                                                                    error);
52125b
 
52125b
         if (!ret) {
52125b
                 return NULL;
52125b
         }
52125b
 
52125b
         g_debug ("GdmClient: connecting to address: %s", address);
52125b
 
52125b
         connection = g_dbus_connection_new_for_address_sync (address,
52125b
                                                              G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
52125b
                                                              NULL,
52125b
                                                              cancellable,
52125b
                                                              error);
52125b
 
52125b
         if (connection == NULL) {
52125b
                 return NULL;
52125b
         }
52125b
 
52125b
         user_verifier = gdm_user_verifier_proxy_new_sync (connection,
52125b
                                                           G_DBUS_PROXY_FLAGS_NONE,
52125b
                                                           NULL,
52125b
                                                           SESSION_DBUS_PATH,
52125b
                                                           cancellable,
52125b
                                                           error);
52125b
 
52125b
+        if (client->priv->user_verifier_for_reauth != NULL) {
52125b
+                g_object_remove_weak_pointer (G_OBJECT (client->priv->user_verifier_for_reauth),
52125b
+                                              (gpointer *)
52125b
+                                              &client->priv->user_verifier_for_reauth);
52125b
+        }
52125b
+
52125b
+        client->priv->user_verifier_for_reauth = user_verifier;
52125b
+
52125b
+        if (user_verifier != NULL) {
52125b
+                g_object_add_weak_pointer (G_OBJECT (client->priv->user_verifier_for_reauth),
52125b
+                                           (gpointer *)
52125b
+                                           &client->priv->user_verifier_for_reauth);
52125b
+        }
52125b
+
52125b
         return user_verifier;
52125b
 }
52125b
 
52125b
 /**
52125b
  * gdm_client_open_reauthentication_channel:
52125b
  * @client: a #GdmClient
52125b
  * @username: user to reauthenticate
52125b
  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
52125b
  * @user_data: The data to pass to @callback
52125b
  * @cancellable: a #GCancellable
52125b
  *
52125b
  * Gets a #GdmUserVerifier object that can be used to
52125b
  * reauthenticate an already logged in user.
52125b
  */
52125b
 void
52125b
 gdm_client_open_reauthentication_channel (GdmClient           *client,
52125b
                                           const char          *username,
52125b
                                           GCancellable        *cancellable,
52125b
                                           GAsyncReadyCallback  callback,
52125b
                                           gpointer             user_data)
52125b
 {
52125b
         GTask *task;
52125b
 
52125b
         g_return_if_fail (GDM_IS_CLIENT (client));
52125b
 
52125b
         task = g_task_new (G_OBJECT (client),
52125b
                            cancellable,
52125b
                            callback,
52125b
                            user_data);
52125b
 
52125b
         g_object_set_data_full (G_OBJECT (task),
52125b
                                 "username",
52125b
                                 g_strdup (username),
52125b
                                 (GDestroyNotify)
52125b
                                 g_free);
52125b
 
52125b
         get_manager (client,
52125b
                      cancellable,
52125b
                      (GAsyncReadyCallback)
52125b
                      on_got_manager_for_reauthentication,
52125b
                      task);
52125b
 }
52125b
 
52125b
 /**
52125b
  * gdm_client_open_reauthentication_channel_finish:
52125b
  * @client: a #GdmClient
52125b
  * @result: The #GAsyncResult from the callback
52125b
  * @error: a #GError
52125b
  *
52125b
  * Finishes an operation started with
52125b
  * gdm_client_open_reauthentication_channel().
52125b
  *
52125b
  * Returns: (transfer full):  a #GdmUserVerifier
52125b
  */
52125b
 GdmUserVerifier *
52125b
 gdm_client_open_reauthentication_channel_finish (GdmClient       *client,
52125b
                                                  GAsyncResult    *result,
52125b
                                                  GError         **error)
52125b
 {
52125b
+        GdmUserVerifier *user_verifier;
52125b
+
52125b
         g_return_val_if_fail (GDM_IS_CLIENT (client), NULL);
52125b
 
52125b
-        return g_task_propagate_pointer (G_TASK (result), error);
52125b
+        user_verifier = g_task_propagate_pointer (G_TASK (result), error);
52125b
+
52125b
+        if (client->priv->user_verifier_for_reauth != NULL) {
52125b
+                g_object_remove_weak_pointer (G_OBJECT (client->priv->user_verifier_for_reauth),
52125b
+                                              (gpointer *)
52125b
+                                              &client->priv->user_verifier_for_reauth);
52125b
+        }
52125b
+
52125b
+        client->priv->user_verifier_for_reauth = user_verifier;
52125b
+
52125b
+        if (user_verifier != NULL) {
52125b
+                g_object_add_weak_pointer (G_OBJECT (client->priv->user_verifier_for_reauth),
52125b
+                                           (gpointer *)
52125b
+                                           &client->priv->user_verifier_for_reauth);
52125b
+        }
52125b
+
52125b
+        return user_verifier;
52125b
 }
52125b
 
52125b
 /**
52125b
  * gdm_client_get_user_verifier_sync:
52125b
  * @client: a #GdmClient
52125b
  * @cancellable: a #GCancellable
52125b
  * @error: a #GError
52125b
  *
52125b
  * Gets a #GdmUserVerifier object that can be used to
52125b
  * verify a user's local account.
52125b
  *
52125b
  * Returns: (transfer full): #GdmUserVerifier or %NULL if not connected
b61949
  */
b61949
 GdmUserVerifier *
b61949
 gdm_client_get_user_verifier_sync (GdmClient     *client,
b61949
                                    GCancellable  *cancellable,
b61949
                                    GError       **error)
b61949
 {
b61949
         g_autoptr(GDBusConnection) connection = NULL;
b61949
 
b61949
         if (client->priv->user_verifier != NULL) {
b61949
                 return g_object_ref (client->priv->user_verifier);
b61949
         }
b61949
 
b61949
         connection = gdm_client_get_connection_sync (client, cancellable, error);
b61949
 
b61949
         if (connection == NULL) {
b61949
                 return NULL;
b61949
         }
b61949
 
b61949
         client->priv->user_verifier = gdm_user_verifier_proxy_new_sync (connection,
b61949
                                                                         G_DBUS_PROXY_FLAGS_NONE,
b61949
                                                                         NULL,
b61949
                                                                         SESSION_DBUS_PATH,
b61949
                                                                         cancellable,
b61949
                                                                         error);
b61949
 
b61949
         if (client->priv->user_verifier != NULL) {
b61949
                 g_object_add_weak_pointer (G_OBJECT (client->priv->user_verifier),
b61949
                                            (gpointer *)
b61949
                                            &client->priv->user_verifier);
b61949
                 if (client->priv->enabled_extensions != NULL) {
b61949
+                        GHashTable *user_verifier_extensions;
b61949
                         gboolean res;
b61949
 
b61949
-                        client->priv->user_verifier_extensions = g_hash_table_new_full (g_str_hash,
b61949
-                                                                                        g_str_equal,
b61949
-                                                                                        NULL,
b61949
-                                                                                        (GDestroyNotify)
b61949
-                                                                                        free_interface_skeleton);
b61949
+                        user_verifier_extensions = g_hash_table_new_full (g_str_hash,
b61949
+                                                                          g_str_equal,
b61949
+                                                                          NULL,
b61949
+                                                                          (GDestroyNotify)
b61949
+                                                                          free_interface_skeleton);
b61949
+                        g_object_set_data_full (G_OBJECT (client->priv->user_verifier),
b61949
+                                                "gdm-client-user-verifier-extensions",
b61949
+                                                user_verifier_extensions,
b61949
+                                                (GDestroyNotify) g_hash_table_unref);
b61949
+
b61949
                         res = gdm_user_verifier_call_enable_extensions_sync (client->priv->user_verifier,
b61949
                                                                             (const char * const *)
b61949
                                                                              client->priv->enabled_extensions,
b61949
                                                                              cancellable,
b61949
                                                                              NULL);
b61949
 
b61949
                         if (res) {
b61949
                                 size_t i;
b61949
                                 for (i = 0; client->priv->enabled_extensions[i] != NULL; i++) {
b61949
                                             if (strcmp (client->priv->enabled_extensions[i],
b61949
                                                         gdm_user_verifier_choice_list_interface_info ()->name) == 0) {
b61949
                                                         GdmUserVerifierChoiceList *choice_list_interface;
b61949
                                                         choice_list_interface = gdm_user_verifier_choice_list_proxy_new_sync (connection,
b61949
                                                                                                                               G_DBUS_PROXY_FLAGS_NONE,
b61949
                                                                                                                               NULL,
b61949
                                                                                                                               SESSION_DBUS_PATH,
b61949
                                                                                                                               cancellable,
b61949
                                                                                                                               NULL);
b61949
                                                         if (choice_list_interface != NULL)
b61949
-                                                                    g_hash_table_insert (client->priv->user_verifier_extensions, client->priv->enabled_extensions[i], choice_list_interface);
b61949
+                                                                    g_hash_table_insert (user_verifier_extensions, client->priv->enabled_extensions[i], choice_list_interface);
b61949
                                             }
b61949
                                 }
b61949
                         }
b61949
                 }
b61949
         }
b61949
 
b61949
         return client->priv->user_verifier;
b61949
 }
b61949
 
b61949
 static void
b61949
 on_connection_for_user_verifier (GdmClient          *client,
b61949
                                  GAsyncResult       *result,
b61949
                                  gpointer            user_data)
b61949
 {
b61949
         GCancellable *cancellable;
b61949
         g_autoptr(GTask)           task = user_data;
b61949
         g_autoptr(GDBusConnection) connection = NULL;
b61949
         g_autoptr(GError)          error = NULL;
b61949
 
b61949
         connection = gdm_client_get_connection_finish (client, result, &error);
b61949
         if (connection == NULL) {
b61949
                 g_task_return_error (task, g_steal_pointer (&error));
b61949
                 return;
b61949
         }
b61949
 
b61949
         cancellable = g_task_get_cancellable (task);
b61949
         gdm_user_verifier_proxy_new (connection,
b61949
                                      G_DBUS_PROXY_FLAGS_NONE,
b61949
                                      NULL,
b61949
                                      SESSION_DBUS_PATH,
52125b
@@ -765,86 +815,102 @@ gdm_client_get_user_verifier (GdmClient           *client,
b61949
                                    g_steal_pointer (&task));
b61949
 }
b61949
 
b61949
 /**
b61949
  * gdm_client_get_user_verifier_finish:
b61949
  * @client: a #GdmClient
b61949
  * @result: The #GAsyncResult from the callback
b61949
  * @error: a #GError
b61949
  *
b61949
  * Finishes an operation started with
b61949
  * gdm_client_get_user_verifier().
b61949
  *
b61949
  * Returns: (transfer full): a #GdmUserVerifier
b61949
  */
b61949
 GdmUserVerifier *
b61949
 gdm_client_get_user_verifier_finish (GdmClient       *client,
b61949
                                      GAsyncResult    *result,
b61949
                                      GError         **error)
b61949
 {
b61949
         GdmUserVerifier *user_verifier;
b61949
 
b61949
         g_return_val_if_fail (GDM_IS_CLIENT (client), NULL);
b61949
 
b61949
         if (client->priv->user_verifier != NULL)
b61949
                 return g_object_ref (client->priv->user_verifier);
b61949
 
b61949
         user_verifier = g_task_propagate_pointer (G_TASK (result), error);
b61949
         if (user_verifier == NULL)
b61949
                 return NULL;
b61949
 
b61949
+        if (client->priv->user_verifier != NULL) {
b61949
+                g_object_remove_weak_pointer (G_OBJECT (client->priv->user_verifier),
b61949
+                                              (gpointer *)
b61949
+                                              &client->priv->user_verifier);
b61949
+        }
b61949
+
52125b
         client->priv->user_verifier = user_verifier;
52125b
 
52125b
-        g_object_add_weak_pointer (G_OBJECT (client->priv->user_verifier),
52125b
-                                   (gpointer *)
52125b
-                                   &client->priv->user_verifier);
52125b
+        if (user_verifier != NULL) {
52125b
+                g_object_add_weak_pointer (G_OBJECT (client->priv->user_verifier),
52125b
+                                           (gpointer *)
52125b
+                                           &client->priv->user_verifier);
52125b
+        }
52125b
 
b61949
         return user_verifier;
b61949
 }
b61949
 
b61949
 /**
b61949
  * gdm_client_get_user_verifier_choice_list:
b61949
  * @client: a #GdmClient
b61949
  *
b61949
  * Gets a #GdmUserVerifierChoiceList object that can be used to
b61949
  * verify a user's local account.
b61949
  *
b61949
  * Returns: (transfer none): #GdmUserVerifierChoiceList or %NULL if user
b61949
  * verifier isn't yet fetched, or daemon doesn't support choice lists
b61949
  */
b61949
 GdmUserVerifierChoiceList *
b61949
 gdm_client_get_user_verifier_choice_list (GdmClient *client)
b61949
 {
b61949
-        if (client->priv->user_verifier_extensions == NULL)
52125b
+        GHashTable *user_verifier_extensions = NULL;
52125b
+
52125b
+        if (client->priv->user_verifier_for_reauth != NULL)
52125b
+                user_verifier_extensions = g_object_get_data (G_OBJECT (client->priv->user_verifier_for_reauth), "gdm-client-user-verifier-extensions");
52125b
+
52125b
+        if (user_verifier_extensions == NULL && client->priv->user_verifier != NULL)
52125b
+                user_verifier_extensions = g_object_get_data (G_OBJECT (client->priv->user_verifier), "gdm-client-user-verifier-extensions");
b61949
+
b61949
+        if (user_verifier_extensions == NULL)
b61949
                 return NULL;
b61949
 
b61949
-        return g_hash_table_lookup (client->priv->user_verifier_extensions,
b61949
+        return g_hash_table_lookup (user_verifier_extensions,
b61949
                                     gdm_user_verifier_choice_list_interface_info ()->name);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_timed_login_details_got (GdmGreeter   *greeter,
b61949
                             GAsyncResult *result)
b61949
 {
b61949
     gdm_greeter_call_get_timed_login_details_finish (greeter, NULL, NULL, NULL, result, NULL);
b61949
 }
b61949
 
b61949
 static void
b61949
 query_for_timed_login_requested_signal (GdmGreeter *greeter)
b61949
 {
b61949
         /* This just makes sure a timed-login-requested signal gets fired
b61949
          * off if appropriate.
b61949
          */
b61949
         gdm_greeter_call_get_timed_login_details (greeter,
b61949
                                                   NULL,
b61949
                                                   (GAsyncReadyCallback)
b61949
                                                   on_timed_login_details_got,
b61949
                                                   NULL);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_greeter_proxy_created (GObject            *source,
b61949
                           GAsyncResult       *result,
b61949
                           gpointer            user_data)
b61949
 {
b61949
         g_autoptr(GTask)  task = user_data;
b61949
         g_autoptr(GError) error = NULL;
52125b
@@ -929,65 +995,73 @@ gdm_client_get_greeter (GdmClient           *client,
52125b
                                    g_steal_pointer (&task));
52125b
 }
52125b
 
52125b
 /**
52125b
  * gdm_client_get_greeter_finish:
52125b
  * @client: a #GdmClient
52125b
  * @result: The #GAsyncResult from the callback
52125b
  * @error: a #GError
52125b
  *
52125b
  * Finishes an operation started with
52125b
  * gdm_client_get_greeter().
52125b
  *
52125b
  * Returns: (transfer full): a #GdmGreeter
52125b
  */
52125b
 GdmGreeter *
52125b
 gdm_client_get_greeter_finish (GdmClient       *client,
52125b
                                GAsyncResult    *result,
52125b
                                GError         **error)
52125b
 {
52125b
         GdmGreeter *greeter;
52125b
 
52125b
         g_return_val_if_fail (GDM_IS_CLIENT (client), NULL);
52125b
 
52125b
         if (client->priv->greeter != NULL)
52125b
                 return g_object_ref (client->priv->greeter);
52125b
 
52125b
         greeter = g_task_propagate_pointer (G_TASK (result), error);
52125b
         if (greeter == NULL)
52125b
                 return NULL;
52125b
 
52125b
+        if (client->priv->greeter != NULL) {
52125b
+                g_object_remove_weak_pointer (G_OBJECT (client->priv->greeter),
52125b
+                                              (gpointer *)
52125b
+                                              &client->priv->greeter);
52125b
+        }
52125b
+
52125b
         client->priv->greeter = greeter;
52125b
 
52125b
-        g_object_add_weak_pointer (G_OBJECT (client->priv->greeter),
52125b
-                                   (gpointer *)
52125b
-                                   &client->priv->greeter);
52125b
+        if (greeter != NULL) {
52125b
+                g_object_add_weak_pointer (G_OBJECT (client->priv->greeter),
52125b
+                                           (gpointer *)
52125b
+                                           &client->priv->greeter);
52125b
+        }
52125b
 
52125b
         return greeter;
52125b
 }
52125b
 
52125b
 /**
52125b
  * gdm_client_get_greeter_sync:
52125b
  * @client: a #GdmClient
52125b
  * @cancellable: a #GCancellable
52125b
  * @error: a #GError
52125b
  *
52125b
  * Gets a #GdmGreeter object that can be used
52125b
  * to do do various login screen related tasks, such
52125b
  * as selecting a users session, and starting that
52125b
  * session.
52125b
  *
52125b
  * Returns: (transfer full): #GdmGreeter or %NULL if caller is not a greeter
52125b
  */
52125b
 GdmGreeter *
52125b
 gdm_client_get_greeter_sync (GdmClient     *client,
52125b
                              GCancellable  *cancellable,
52125b
                              GError       **error)
52125b
 {
52125b
         g_autoptr(GDBusConnection) connection = NULL;
52125b
 
52125b
         if (client->priv->greeter != NULL) {
52125b
                 return g_object_ref (client->priv->greeter);
52125b
         }
52125b
 
52125b
         connection = gdm_client_get_connection_sync (client, cancellable, error);
52125b
 
52125b
@@ -1099,65 +1173,73 @@ gdm_client_get_remote_greeter (GdmClient           *client,
52125b
                                    g_steal_pointer (&task));
52125b
 }
52125b
 
52125b
 /**
52125b
  * gdm_client_get_remote_greeter_finish:
52125b
  * @client: a #GdmClient
52125b
  * @result: The #GAsyncResult from the callback
52125b
  * @error: a #GError
52125b
  *
52125b
  * Finishes an operation started with
52125b
  * gdm_client_get_remote_greeter().
52125b
  *
52125b
  * Returns: (transfer full): a #GdmRemoteGreeter
52125b
  */
52125b
 GdmRemoteGreeter *
52125b
 gdm_client_get_remote_greeter_finish (GdmClient     *client,
52125b
                                       GAsyncResult  *result,
52125b
                                       GError       **error)
52125b
 {
52125b
         GdmRemoteGreeter *remote_greeter;
52125b
 
52125b
         g_return_val_if_fail (GDM_IS_CLIENT (client), NULL);
52125b
 
52125b
         if (client->priv->remote_greeter != NULL)
52125b
                 return g_object_ref (client->priv->remote_greeter);
52125b
 
52125b
         remote_greeter = g_task_propagate_pointer (G_TASK (result), error);
52125b
         if (remote_greeter == NULL)
52125b
                 return NULL;
52125b
 
52125b
+        if (client->priv->remote_greeter != NULL) {
52125b
+                g_object_remove_weak_pointer (G_OBJECT (client->priv->remote_greeter),
52125b
+                                              (gpointer *)
52125b
+                                              &client->priv->remote_greeter);
52125b
+        }
52125b
+
52125b
         client->priv->remote_greeter = remote_greeter;
52125b
 
52125b
-        g_object_add_weak_pointer (G_OBJECT (client->priv->remote_greeter),
52125b
-                                   (gpointer *)
52125b
-                                   &client->priv->remote_greeter);
52125b
+        if (remote_greeter != NULL) {
52125b
+                g_object_add_weak_pointer (G_OBJECT (client->priv->remote_greeter),
52125b
+                                           (gpointer *)
52125b
+                                           &client->priv->remote_greeter);
52125b
+        }
52125b
 
52125b
         return remote_greeter;
52125b
 }
52125b
 
52125b
 /**
52125b
  * gdm_client_get_remote_greeter_sync:
52125b
  * @client: a #GdmClient
52125b
  * @cancellable: a #GCancellable
52125b
  * @error: a #GError
52125b
  *
52125b
  * Gets a #GdmRemoteGreeter object that can be used
52125b
  * to do do various remote login screen related tasks,
52125b
  * such as disconnecting.
52125b
  *
52125b
  * Returns: (transfer full): #GdmRemoteGreeter or %NULL if caller is not remote
52125b
  */
52125b
 GdmRemoteGreeter *
52125b
 gdm_client_get_remote_greeter_sync (GdmClient     *client,
52125b
                                     GCancellable  *cancellable,
52125b
                                     GError       **error)
52125b
 {
52125b
         g_autoptr(GDBusConnection) connection = NULL;
52125b
 
52125b
         if (client->priv->remote_greeter != NULL) {
52125b
                 return g_object_ref (client->priv->remote_greeter);
52125b
         }
52125b
 
52125b
         connection = gdm_client_get_connection_sync (client, cancellable, error);
52125b
 
52125b
         if (connection == NULL) {
52125b
@@ -1267,65 +1349,73 @@ gdm_client_get_chooser (GdmClient           *client,
52125b
                                    g_steal_pointer (&task));
52125b
 }
52125b
 
52125b
 /**
52125b
  * gdm_client_get_chooser_finish:
52125b
  * @client: a #GdmClient
52125b
  * @result: The #GAsyncResult from the callback
52125b
  * @error: a #GError
52125b
  *
52125b
  * Finishes an operation started with
52125b
  * gdm_client_get_chooser().
52125b
  *
52125b
  * Returns: (transfer full): a #GdmChooser
52125b
  */
52125b
 GdmChooser *
52125b
 gdm_client_get_chooser_finish (GdmClient       *client,
52125b
                                GAsyncResult    *result,
52125b
                                GError         **error)
52125b
 {
52125b
         GdmChooser *chooser;
52125b
 
52125b
         g_return_val_if_fail (GDM_IS_CLIENT (client), NULL);
52125b
 
52125b
         if (client->priv->chooser != NULL)
52125b
                 return g_object_ref (client->priv->chooser);
52125b
 
52125b
         chooser = g_task_propagate_pointer (G_TASK (result), error);
52125b
         if (chooser == NULL)
52125b
                 return NULL;
52125b
 
52125b
+        if (client->priv->chooser != NULL) {
52125b
+                g_object_remove_weak_pointer (G_OBJECT (client->priv->chooser),
52125b
+                                              (gpointer *)
52125b
+                                              &client->priv->chooser);
52125b
+        }
52125b
+
52125b
         client->priv->chooser = chooser;
52125b
 
52125b
-        g_object_add_weak_pointer (G_OBJECT (client->priv->chooser),
52125b
-                                   (gpointer *)
52125b
-                                   &client->priv->chooser);
52125b
+        if (chooser != NULL) {
52125b
+                g_object_add_weak_pointer (G_OBJECT (client->priv->chooser),
52125b
+                                           (gpointer *)
52125b
+                                           &client->priv->chooser);
52125b
+        }
52125b
 
52125b
         return chooser;
52125b
 }
52125b
 
52125b
 /**
52125b
  * gdm_client_get_chooser_sync:
52125b
  * @client: a #GdmClient
52125b
  * @cancellable: a #GCancellable
52125b
  * @error: a #GError
52125b
  *
52125b
  * Gets a #GdmChooser object that can be used
52125b
  * to do do various XDMCP chooser related tasks, such
52125b
  * as selecting a host or disconnecting.
52125b
  *
52125b
  * Returns: (transfer full): #GdmChooser or %NULL if caller is not a chooser
52125b
  */
52125b
 GdmChooser *
52125b
 gdm_client_get_chooser_sync (GdmClient     *client,
52125b
                              GCancellable  *cancellable,
52125b
                              GError       **error)
52125b
 {
52125b
         g_autoptr(GDBusConnection) connection = NULL;
52125b
 
52125b
         if (client->priv->chooser != NULL) {
52125b
                 return g_object_ref (client->priv->chooser);
52125b
         }
52125b
 
52125b
         connection = gdm_client_get_connection_sync (client, cancellable, error);
52125b
 
52125b
         if (connection == NULL) {
52125b
@@ -1355,60 +1445,67 @@ gdm_client_class_init (GdmClientClass *klass)
52125b
 
52125b
         object_class->finalize = gdm_client_finalize;
52125b
 
52125b
         g_type_class_add_private (klass, sizeof (GdmClientPrivate));
52125b
 
52125b
 }
52125b
 
52125b
 static void
52125b
 gdm_client_init (GdmClient *client)
52125b
 {
52125b
 
52125b
         client->priv = GDM_CLIENT_GET_PRIVATE (client);
52125b
 }
52125b
 
52125b
 static void
52125b
 gdm_client_finalize (GObject *object)
52125b
 {
52125b
         GdmClient *client;
52125b
 
52125b
         g_return_if_fail (object != NULL);
52125b
         g_return_if_fail (GDM_IS_CLIENT (object));
52125b
 
52125b
         client = GDM_CLIENT (object);
52125b
 
52125b
         g_return_if_fail (client->priv != NULL);
52125b
 
52125b
         if (client->priv->user_verifier != NULL) {
52125b
                 g_object_remove_weak_pointer (G_OBJECT (client->priv->user_verifier),
52125b
                                               (gpointer *)
52125b
                                               &client->priv->user_verifier);
52125b
+
52125b
+        }
52125b
+
52125b
+        if (client->priv->user_verifier_for_reauth != NULL) {
52125b
+                g_object_remove_weak_pointer (G_OBJECT (client->priv->user_verifier_for_reauth),
52125b
+                                              (gpointer *)
52125b
+                                              &client->priv->user_verifier_for_reauth);
52125b
         }
52125b
 
52125b
         if (client->priv->greeter != NULL) {
52125b
                 g_object_remove_weak_pointer (G_OBJECT (client->priv->greeter),
52125b
                                               (gpointer *)
52125b
                                               &client->priv->greeter);
52125b
         }
52125b
 
52125b
         if (client->priv->remote_greeter != NULL) {
52125b
                 g_object_remove_weak_pointer (G_OBJECT (client->priv->remote_greeter),
52125b
                                               (gpointer *)
52125b
                                               &client->priv->remote_greeter);
52125b
         }
52125b
 
52125b
         if (client->priv->chooser != NULL) {
52125b
                 g_object_remove_weak_pointer (G_OBJECT (client->priv->chooser),
52125b
                                               (gpointer *)
52125b
                                               &client->priv->chooser);
52125b
         }
52125b
 
52125b
         g_strfreev (client->priv->enabled_extensions);
52125b
 
52125b
         G_OBJECT_CLASS (gdm_client_parent_class)->finalize (object);
52125b
 }
52125b
 
52125b
 GdmClient *
52125b
 gdm_client_new (void)
52125b
 {
52125b
         if (client_object != NULL) {
52125b
                 g_object_ref (client_object);
b61949
-- 
52125b
2.25.1
b61949