summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2018-05-02 11:47:34 +0200
committerZeeshan Ali <zeenix@collabora.co.uk>2018-05-02 23:09:42 +0200
commita325247a1e6d658ab5e54227e1e81e958fc4f544 (patch)
tree2645b5c9d368e2cfd5fbd40aa6daa42158f94932
parentc8dc5bc0318293dbc9007946e92a10dba3a57d54 (diff)
downloadgeoclue-a325247a1e6d658ab5e54227e1e81e958fc4f544.tar.gz
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
-rw-r--r--src/gclue-service-client.c80
1 files changed, 71 insertions, 9 deletions
diff --git a/src/gclue-service-client.c b/src/gclue-service-client.c
index 03219ad..97486f8 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);
@@ -43,12 +44,16 @@ G_DEFINE_TYPE_WITH_CODE (GClueServiceClient,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
gclue_service_client_initable_iface_init));
+typedef struct _StartData StartData;
+
struct _GClueServiceClientPrivate
{
GClueClientInfo *client_info;
const char *path;
GDBusConnection *connection;
GClueAgent *agent_proxy;
+ StartData *pending_auth_start_data;
+ guint pending_auth_timeout_id;
GClueServiceLocation *location;
GClueServiceLocation *prev_location;
@@ -328,13 +333,13 @@ on_agent_props_changed (GDBusProxy *agent_proxy,
g_variant_iter_free (iter);
}
-typedef struct
+struct _StartData
{
GClueServiceClient *client;
GDBusMethodInvocation *invocation;
char *desktop_id;
GClueAccuracyLevel accuracy_level;
-} StartData;
+};
static void
start_data_free (StartData *data)
@@ -449,6 +454,56 @@ handle_post_agent_check_auth (StartData *data)
}
static gboolean
+handle_pending_auth (gpointer user_data)
+{
+ GClueServiceClientPrivate *priv = GCLUE_SERVICE_CLIENT (user_data)->priv;
+ StartData *data = priv->pending_auth_start_data;
+ guint32 uid;
+
+ uid = gclue_client_info_get_user_id (priv->client_info);
+ 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);
+ }
+
+ priv->pending_auth_timeout_id = 0;
+ priv->pending_auth_start_data = NULL;
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+set_pending_auth_timeout_enable (GClueDBusClient *client)
+{
+ GClueServiceClientPrivate *priv = GCLUE_SERVICE_CLIENT (client)->priv;
+
+ if (priv->pending_auth_timeout_id > 0)
+ return;
+ priv->pending_auth_timeout_id = g_timeout_add_seconds
+ (DEFAULT_AGENT_STARTUP_WAIT_SECS, handle_pending_auth, client);
+}
+
+static void
+set_pending_auth_timeout_disable (GClueDBusClient *client)
+{
+ GClueServiceClientPrivate *priv = GCLUE_SERVICE_CLIENT (client)->priv;
+
+ if (priv->pending_auth_timeout_id == 0)
+ return;
+
+ g_source_remove (priv->pending_auth_timeout_id);
+ priv->pending_auth_timeout_id = 0;
+}
+
+static gboolean
gclue_service_client_handle_start (GClueDBusClient *client,
GDBusMethodInvocation *invocation)
{
@@ -527,13 +582,17 @@ 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);
+ /* Already a pending Start()? Denied! */
+ if (priv->pending_auth_start_data) {
+ g_dbus_method_invocation_return_error_literal
+ (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ "An authorization request is already pending");
+ } else {
+ priv->pending_auth_start_data = data;
+ set_pending_auth_timeout_enable (client);
+ }
return TRUE;
}
@@ -560,6 +619,8 @@ gclue_service_client_finalize (GObject *object)
g_clear_pointer (&priv->path, g_free);
g_clear_object (&priv->connection);
+ set_pending_auth_timeout_disable (GCLUE_DBUS_CLIENT (object));
+ g_clear_pointer (&priv->pending_auth_start_data, start_data_free);
if (priv->agent_proxy != NULL)
g_signal_handlers_disconnect_by_func
(priv->agent_proxy,
@@ -633,6 +694,7 @@ gclue_service_client_set_property (GObject *object,
"g-properties-changed",
G_CALLBACK (on_agent_props_changed),
object);
+ handle_pending_auth (client);
break;
default: