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',