From be0a2a4227640115694410dc4c0dd283a8bd379b Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 2 May 2018 11:47:34 +0200 Subject: [PATCH] service-client: Delay "no agent" authorization decision To avoid applications being denied access to location services when gnome-shell hasn't had a chance to register its agent, either because Geoclue got auto-started by the application, or because the shell hasn't finished starting up, delay the authorization check until either an agent appears, or 5 seconds after the application requested the authorization. https://bugs.freedesktop.org/show_bug.cgi?id=106236 --- src/gclue-service-client.c | 71 ++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/src/gclue-service-client.c b/src/gclue-service-client.c index 03219ad..48fb821 100644 --- a/src/gclue-service-client.c +++ b/src/gclue-service-client.c @@ -29,6 +29,7 @@ #include "gclue-config.h" #define DEFAULT_ACCURACY_LEVEL GCLUE_ACCURACY_LEVEL_CITY +#define DEFAULT_AGENT_STARTUP_WAIT_SECS 5 static void gclue_service_client_client_iface_init (GClueDBusClientIface *iface); @@ -49,6 +50,8 @@ struct _GClueServiceClientPrivate const char *path; GDBusConnection *connection; GClueAgent *agent_proxy; + GList *pending_auths; + guint pending_auths_timeout_id; GClueServiceLocation *location; GClueServiceLocation *prev_location; @@ -448,6 +451,58 @@ handle_post_agent_check_auth (StartData *data) data); } +static gboolean +handle_pending_auths (gpointer user_data) +{ + GClueServiceClientPrivate *priv = GCLUE_SERVICE_CLIENT (user_data)->priv; + GList *l; + guint32 uid; + + uid = gclue_client_info_get_user_id (priv->client_info); + + for (l = priv->pending_auths; l != NULL; l = l->next) { + StartData *data = l->data; + + if (priv->agent_proxy == NULL) { + g_dbus_method_invocation_return_error (data->invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "'%s' disallowed, no agent " + "for UID %u", + data->desktop_id, + uid); + start_data_free (data); + } else { + handle_post_agent_check_auth (data); + } + } + + g_clear_pointer (&priv->pending_auths, g_list_free); + priv->pending_auths = NULL; + priv->pending_auths_timeout_id = 0; + + return G_SOURCE_REMOVE; +} + +static void +set_pending_auths_timeout (GClueDBusClient *client, + gboolean enable) +{ + GClueServiceClientPrivate *priv = GCLUE_SERVICE_CLIENT (client)->priv; + + if (enable) { + if (priv->pending_auths_timeout_id > 0) + return; + priv->pending_auths_timeout_id = g_timeout_add_seconds + (DEFAULT_AGENT_STARTUP_WAIT_SECS, handle_pending_auths, client); + } else { + if (priv->pending_auths_timeout_id == 0) + return; + g_source_remove (priv->pending_auths_timeout_id); + priv->pending_auths_timeout_id = 0; + } +} + static gboolean gclue_service_client_handle_start (GClueDBusClient *client, GDBusMethodInvocation *invocation) @@ -527,13 +582,8 @@ gclue_service_client_handle_start (GClueDBusClient *client, /* No agent == No authorization */ if (priv->agent_proxy == NULL) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_ACCESS_DENIED, - "'%s' disallowed, no agent " - "for UID %u", - desktop_id, - uid); + priv->pending_auths = g_list_prepend (priv->pending_auths, data); + set_pending_auths_timeout (client, TRUE); return TRUE; } @@ -560,6 +610,12 @@ gclue_service_client_finalize (GObject *object) g_clear_pointer (&priv->path, g_free); g_clear_object (&priv->connection); + set_pending_auths_timeout (GCLUE_DBUS_CLIENT (object), FALSE); + if (priv->pending_auths != NULL) { + g_list_free_full (priv->pending_auths, + (GDestroyNotify) start_data_free); + priv->pending_auths = NULL; + } if (priv->agent_proxy != NULL) g_signal_handlers_disconnect_by_func (priv->agent_proxy, @@ -633,6 +689,7 @@ gclue_service_client_set_property (GObject *object, "g-properties-changed", G_CALLBACK (on_agent_props_changed), object); + handle_pending_auths (client); break; default: -- 2.17.0