diff --git a/src/backends/meta-a11y-manager.c b/src/backends/meta-a11y-manager.c
index 5001d114a..c51e2f712 100644
--- a/src/backends/meta-a11y-manager.c
+++ b/src/backends/meta-a11y-manager.c
@@ -21,6 +21,7 @@
#include "config.h"
#include "backends/meta-a11y-manager.h"
+#include "backends/meta-dbus-access-checker.h"
#include "meta/meta-backend.h"
#include "meta/meta-context.h"
#include "meta/util.h"
@@ -78,6 +79,8 @@ typedef struct _MetaA11yManager
GList *key_grabbers;
GHashTable *grabbed_keypresses;
GHashTable *all_grabbed_modifiers;
+
+ MetaDbusAccessChecker *access_checker;
} MetaA11yManager;
G_DEFINE_TYPE (MetaA11yManager, meta_a11y_manager, G_TYPE_OBJECT)
@@ -182,6 +185,28 @@ ensure_key_grabber (MetaA11yManager *a11y_manager,
return grabber;
}
+static gboolean
+check_access (GDBusInterfaceSkeleton *skeleton,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ MetaA11yManager *a11y_manager = META_A11Y_MANAGER (user_data);
+ const char *sender =
+ g_dbus_method_invocation_get_sender (invocation);
+
+ if (!meta_dbus_access_checker_is_sender_allowed (a11y_manager->access_checker,
+ sender))
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ "Access denied");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static gboolean
handle_grab_keyboard (MetaDBusKeyboardMonitor *skeleton,
GDBusMethodInvocation *invocation,
@@ -279,9 +304,12 @@ on_bus_acquired (GDBusConnection *connection,
gpointer user_data)
{
MetaA11yManager *manager = user_data;
+ MetaContext *context = meta_backend_get_context (manager->backend);
manager->keyboard_monitor_skeleton = meta_dbus_keyboard_monitor_skeleton_new ();
+ g_signal_connect (manager->keyboard_monitor_skeleton, "g-authorize-method",
+ G_CALLBACK (check_access), manager);
g_signal_connect (manager->keyboard_monitor_skeleton, "handle-grab-keyboard",
G_CALLBACK (handle_grab_keyboard), manager);
g_signal_connect (manager->keyboard_monitor_skeleton, "handle-ungrab-keyboard",
@@ -297,6 +325,10 @@ on_bus_acquired (GDBusConnection *connection,
connection,
"/org/freedesktop/a11y/Manager",
NULL);
+
+ manager->access_checker = meta_dbus_access_checker_new (connection, context);
+ meta_dbus_access_checker_allow_sender (manager->access_checker,
+ "org.gnome.Orca.KeyboardMonitor");
}
static void
@@ -323,6 +355,7 @@ meta_a11y_manager_finalize (GObject *object)
g_list_free_full (a11y_manager->key_grabbers,
(GDestroyNotify) key_grabber_free);
g_clear_object (&a11y_manager->keyboard_monitor_skeleton);
+ g_clear_object (&a11y_manager->access_checker);
g_clear_pointer (&a11y_manager->grabbed_keypresses, g_hash_table_destroy);
g_clear_pointer (&a11y_manager->all_grabbed_modifiers, g_hash_table_destroy);
g_bus_unown_name (a11y_manager->dbus_name_id);
diff --git a/src/backends/meta-dbus-access-checker.c b/src/backends/meta-dbus-access-checker.c
new file mode 100644
index 000000000..0ace12607
--- /dev/null
+++ b/src/backends/meta-dbus-access-checker.c
@@ -0,0 +1,212 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright 2024 GNOME Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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 .
+ *
+ */
+
+#include "config.h"
+
+#include "meta-dbus-access-checker.h"
+
+#include "core/meta-context-private.h"
+
+enum
+{
+ PROP_0,
+ PROP_CONNECTION,
+ PROP_CONTEXT,
+ N_PROPS
+};
+
+static GParamSpec *props[N_PROPS];
+
+typedef struct _AllowedSender AllowedSender;
+
+struct _AllowedSender
+{
+ char *name;
+ char *name_owner;
+ guint watch_id;
+};
+
+struct _MetaDbusAccessChecker
+{
+ GObject parent_instance;
+ GDBusConnection *connection;
+ GPtrArray *allowed_senders;
+ MetaContext *context;
+};
+
+G_DEFINE_TYPE (MetaDbusAccessChecker, meta_dbus_access_checker, G_TYPE_OBJECT)
+
+static void
+name_appeared_cb (GDBusConnection *connection,
+ const char *name,
+ const char *name_owner,
+ gpointer user_data)
+{
+ AllowedSender *allowed_sender = user_data;
+
+ allowed_sender->name_owner = g_strdup (name_owner);
+}
+
+static void
+name_vanished_cb (GDBusConnection *connection,
+ const char *name,
+ gpointer user_data)
+{
+ AllowedSender *allowed_sender = user_data;
+
+ g_clear_pointer (&allowed_sender->name_owner, g_free);
+}
+
+static AllowedSender *
+allowed_sender_new (MetaDbusAccessChecker *self,
+ const char *name)
+{
+ AllowedSender *allowed_sender;
+
+ allowed_sender = g_new0 (AllowedSender, 1);
+ allowed_sender->name = g_strdup (name);
+ allowed_sender->watch_id =
+ g_bus_watch_name_on_connection (self->connection,
+ name,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ name_appeared_cb,
+ name_vanished_cb,
+ allowed_sender,
+ NULL);
+
+ return allowed_sender;
+}
+
+static void
+allowed_sender_free (AllowedSender *allowed_sender)
+{
+ g_clear_pointer (&allowed_sender->name, g_free);
+ g_clear_pointer (&allowed_sender->name_owner, g_free);
+ g_bus_unwatch_name (allowed_sender->watch_id);
+ g_free (allowed_sender);
+}
+
+static void
+meta_dbus_access_checker_init (MetaDbusAccessChecker *self)
+{
+ self->allowed_senders =
+ g_ptr_array_new_with_free_func ((GDestroyNotify) allowed_sender_free);
+}
+
+static void
+meta_dbus_access_checker_finalize (GObject *object)
+{
+ MetaDbusAccessChecker *self =
+ META_DBUS_ACCESS_CHECKER (object);
+
+ g_clear_pointer (&self->allowed_senders, g_ptr_array_unref);
+ g_clear_object (&self->connection);
+
+ G_OBJECT_CLASS (meta_dbus_access_checker_parent_class)->finalize (object);
+}
+
+static void
+meta_dbus_access_checker_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MetaDbusAccessChecker *self = META_DBUS_ACCESS_CHECKER (object);
+
+ switch (prop_id)
+ {
+ case PROP_CONNECTION:
+ self->connection = g_value_dup_object (value);
+ break;
+ case PROP_CONTEXT:
+ self->context = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+meta_dbus_access_checker_class_init (MetaDbusAccessCheckerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = meta_dbus_access_checker_finalize;
+ object_class->set_property = meta_dbus_access_checker_set_property;
+
+ props[PROP_CONNECTION] =
+ g_param_spec_object ("connection", NULL, NULL,
+ G_TYPE_DBUS_CONNECTION,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ props[PROP_CONTEXT] =
+ g_param_spec_object ("context", NULL, NULL,
+ META_TYPE_CONTEXT,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPS, props);
+}
+
+MetaDbusAccessChecker *
+meta_dbus_access_checker_new (GDBusConnection *connection,
+ MetaContext *context)
+{
+ return g_object_new (META_TYPE_DBUS_ACCESS_CHECKER,
+ "connection", connection,
+ "context", context,
+ NULL);
+}
+
+void
+meta_dbus_access_checker_allow_sender (MetaDbusAccessChecker *self,
+ const char *name)
+{
+ AllowedSender *allowed_sender;
+
+ allowed_sender = allowed_sender_new (self, name);
+ g_ptr_array_add (self->allowed_senders, allowed_sender);
+}
+
+gboolean
+meta_dbus_access_checker_is_sender_allowed (MetaDbusAccessChecker *self,
+ const char *sender_name)
+{
+ int i;
+
+ if (meta_context_get_unsafe_mode (self->context))
+ return TRUE;
+
+ for (i = 0; i < self->allowed_senders->len; i++)
+ {
+ AllowedSender *allowed_sender;
+
+ allowed_sender = g_ptr_array_index (self->allowed_senders, i);
+
+ if (sender_name &&
+ g_strcmp0 (allowed_sender->name_owner, sender_name) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/src/backends/meta-dbus-access-checker.h b/src/backends/meta-dbus-access-checker.h
new file mode 100644
index 000000000..acbb942c0
--- /dev/null
+++ b/src/backends/meta-dbus-access-checker.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2024 GNOME Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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 .
+ *
+ */
+
+#pragma once
+
+#include
+#include
+
+#include "meta/meta-context.h"
+
+#define META_TYPE_DBUS_ACCESS_CHECKER (meta_dbus_access_checker_get_type())
+G_DECLARE_FINAL_TYPE (MetaDbusAccessChecker,
+ meta_dbus_access_checker,
+ META, DBUS_ACCESS_CHECKER,
+ GObject)
+
+MetaDbusAccessChecker * meta_dbus_access_checker_new (GDBusConnection *connection,
+ MetaContext *context);
+
+void meta_dbus_access_checker_allow_sender (MetaDbusAccessChecker *self,
+ const char *name);
+
+gboolean meta_dbus_access_checker_is_sender_allowed (MetaDbusAccessChecker *self,
+ const char *sender_name);
diff --git a/src/core/meta-context-private.h b/src/core/meta-context-private.h
index a53f901fb..c5120f2e3 100644
--- a/src/core/meta-context-private.h
+++ b/src/core/meta-context-private.h
@@ -70,6 +70,8 @@ const char * meta_context_get_gnome_wm_keybindings (MetaContext *context);
void meta_context_set_unsafe_mode (MetaContext *context,
gboolean enable);
+gboolean meta_context_get_unsafe_mode (MetaContext *context);
+
#ifdef HAVE_WAYLAND
META_EXPORT_TEST
MetaServiceChannel * meta_context_get_service_channel (MetaContext *context);
diff --git a/src/core/meta-context.c b/src/core/meta-context.c
index 996dcdd07..b5c51009a 100644
--- a/src/core/meta-context.c
+++ b/src/core/meta-context.c
@@ -620,6 +620,14 @@ meta_context_destroy (MetaContext *context)
g_object_unref (context);
}
+gboolean
+meta_context_get_unsafe_mode (MetaContext *context)
+{
+ MetaContextPrivate *priv = meta_context_get_instance_private (context);
+
+ return priv->unsafe_mode;
+}
+
void
meta_context_set_unsafe_mode (MetaContext *context,
gboolean enable)
diff --git a/src/meson.build b/src/meson.build
index 918b67e11..cc1144d38 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -213,6 +213,8 @@ mutter_sources = [
'backends/meta-cursor-sprite-xcursor.h',
'backends/meta-cursor-tracker.c',
'backends/meta-cursor-tracker-private.h',
+ 'backends/meta-dbus-access-checker.c',
+ 'backends/meta-dbus-access-checker.h',
'backends/meta-dbus-session-manager.c',
'backends/meta-dbus-session-manager.h',
'backends/meta-dbus-session-watcher.c',