All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Frédéric Danis" <frederic.danis@collabora.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ 2/7] client/bluetoothctl: make admin.allow controller-aware
Date: Thu,  2 Jul 2026 10:36:36 +0200	[thread overview]
Message-ID: <20260702083641.378994-2-frederic.danis@collabora.com> (raw)
In-Reply-To: <20260702083641.378994-1-frederic.danis@collabora.com>

Teach admin.allow to target the selected default controller when no
controller is provided, and to accept an explicit [ctrl] argument.

Replace single cached AdminPolicy proxies with per-controller proxy
lookup keyed by controller object path, so controller selection changes
are respected.

Export controller lookup/default helpers and shared controller
completion from main.c for reuse by admin.c.

Assisted-by: GPT:GPT-5.3-Codex
---
 client/admin.c | 114 ++++++++++++++++++++++++++++++++++++++-----------
 client/admin.h |   4 ++
 client/main.c  |  25 +++++++++--
 3 files changed, 116 insertions(+), 27 deletions(-)

diff --git a/client/admin.c b/client/admin.c
index dc218ed2c..584d4630b 100644
--- a/client/admin.c
+++ b/client/admin.c
@@ -16,6 +16,7 @@
 #include <string.h>
 #include <stdlib.h>
 
+#include "bluetooth/bluetooth.h"
 #include "gdbus/gdbus.h"
 #include "src/shared/shell.h"
 
@@ -23,27 +24,79 @@
 #define _GNU_SOURCE
 
 static DBusConnection *dbus_conn;
-static GList *admin_proxies;
-static GDBusProxy *set_proxy;
-static GDBusProxy *status_proxy;
+static GList *set_proxies;
+static GList *status_proxies;
 
 static void admin_menu_pre_run(const struct bt_shell_menu *menu);
 
-static void admin_policy_set_set_proxy(GDBusProxy *proxy)
+static GDBusProxy *admin_policy_find_proxy(GList *proxies,
+						const char *path)
 {
-	set_proxy = proxy;
+	GList *list;
+
+	for (list = g_list_first(proxies); list; list = g_list_next(list)) {
+		GDBusProxy *proxy = list->data;
+
+		if (!strcmp(g_dbus_proxy_get_path(proxy), path))
+			return proxy;
+	}
+
+	return NULL;
+}
+
+static GDBusProxy *admin_policy_get_status_proxy(const char *controller_path)
+{
+	if (!controller_path)
+		return NULL;
+
+	return admin_policy_find_proxy(status_proxies, controller_path);
+}
+
+static GDBusProxy *admin_policy_get_set_proxy(const char *controller_path)
+{
+	if (!controller_path)
+		return NULL;
+
+	return admin_policy_find_proxy(set_proxies, controller_path);
 }
 
-static void admin_policy_set_status_proxy(GDBusProxy *proxy)
+static GDBusProxy *admin_policy_get_controller(int argc, char *argv[],
+						int *arg_index)
 {
-	status_proxy = proxy;
+	GDBusProxy *controller;
+
+	*arg_index = 1;
+
+	if (argc > 1 && strlen(argv[1])) {
+		controller = bluetoothctl_find_controller(argv[1]);
+		if (controller) {
+			*arg_index = 2;
+			return controller;
+		}
+
+		if (bachk(argv[1]) == 0) {
+			bt_shell_printf("Controller %s not available\n",
+								argv[1]);
+			return NULL;
+		}
+	}
+
+	controller = bluetoothctl_get_default_controller();
+	if (controller)
+		return controller;
+
+	bt_shell_printf("No default controller available\n");
+	return NULL;
 }
 
-static void admin_policy_read_service_allowlist(DBusConnection *dbus_conn)
+static void admin_policy_read_service_allowlist(GDBusProxy *controller)
 {
 	DBusMessageIter iter, subiter;
+	GDBusProxy *status_proxy;
 	char *uuid = NULL;
+	const char *controller_path = g_dbus_proxy_get_path(controller);
 
+	status_proxy = admin_policy_get_status_proxy(controller_path);
 	if (!status_proxy || !g_dbus_proxy_get_property(status_proxy,
 						"ServiceAllowList", &iter)) {
 		bt_shell_printf("Failed to get property\n");
@@ -106,10 +159,14 @@ static void set_service_reply(DBusMessage *message, void *user_data)
 	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
-static void admin_policy_set_service_allowlist(int argc, char *argv[])
+static void admin_policy_set_service_allowlist(GDBusProxy *controller,
+						int argc, char *argv[])
 {
 	struct uuid_list_data data;
+	GDBusProxy *set_proxy;
+	const char *controller_path = g_dbus_proxy_get_path(controller);
 
+	set_proxy = admin_policy_get_set_proxy(controller_path);
 	if (!set_proxy) {
 		bt_shell_printf("Set proxy not ready\n");
 		return bt_shell_noninteractive_quit(EXIT_FAILURE);
@@ -128,15 +185,23 @@ static void admin_policy_set_service_allowlist(int argc, char *argv[])
 
 static void cmd_admin_allow(int argc, char *argv[])
 {
-	if (argc <= 1) {
-		admin_policy_read_service_allowlist(dbus_conn);
+	GDBusProxy *controller;
+	int arg_index;
+
+	controller = admin_policy_get_controller(argc, argv, &arg_index);
+	if (!controller)
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+
+	if (argc <= arg_index) {
+		admin_policy_read_service_allowlist(controller);
 		return;
 	}
 
-	if (strcmp(argv[1], "clear") == 0)
-		argc--;
+	if (strcmp(argv[arg_index], "clear") == 0)
+		arg_index++;
 
-	admin_policy_set_service_allowlist(argc - 1, argv + 1);
+	admin_policy_set_service_allowlist(controller, argc - arg_index,
+						argv + arg_index);
 }
 
 static const struct bt_shell_menu admin_menu = {
@@ -144,15 +209,15 @@ static const struct bt_shell_menu admin_menu = {
 	.desc = "Admin Policy Submenu",
 	.pre_run = admin_menu_pre_run,
 	.entries = {
-	{ "allow", "[clear/uuid1 uuid2 ...]", cmd_admin_allow,
-				"Allow service UUIDs and block rest of them"},
+	{ "allow", "[ctrl] [clear/uuid1 uuid2 ...]", cmd_admin_allow,
+				"Allow service UUIDs and block rest of them",
+				bluetoothctl_controller_generator},
 	{} },
 };
 
 static void admin_policy_status_added(GDBusProxy *proxy)
 {
-	admin_proxies = g_list_append(admin_proxies, proxy);
-	admin_policy_set_status_proxy(proxy);
+	status_proxies = g_list_append(status_proxies, proxy);
 }
 
 static void proxy_added(GDBusProxy *proxy, void *user_data)
@@ -162,15 +227,14 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
 	interface = g_dbus_proxy_get_interface(proxy);
 
 	if (!strcmp(interface, "org.bluez.AdminPolicySet1"))
-		admin_policy_set_set_proxy(proxy);
+		set_proxies = g_list_append(set_proxies, proxy);
 	else if (!strcmp(interface, "org.bluez.AdminPolicyStatus1"))
 		admin_policy_status_added(proxy);
 }
 
 static void admin_policy_status_removed(GDBusProxy *proxy)
 {
-	admin_proxies = g_list_remove(admin_proxies, proxy);
-	admin_policy_set_status_proxy(NULL);
+	status_proxies = g_list_remove(status_proxies, proxy);
 }
 
 static void proxy_removed(GDBusProxy *proxy, void *user_data)
@@ -180,7 +244,7 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 	interface = g_dbus_proxy_get_interface(proxy);
 
 	if (!strcmp(interface, "org.bluez.AdminPolicySet1"))
-		admin_policy_set_set_proxy(NULL);
+		set_proxies = g_list_remove(set_proxies, proxy);
 	else if (!strcmp(interface, "org.bluez.AdminPolicyStatus1"))
 		admin_policy_status_removed(proxy);
 }
@@ -189,8 +253,10 @@ static GDBusClient *client;
 
 static void disconnect_handler(DBusConnection *connection, void *user_data)
 {
-	g_list_free_full(admin_proxies, NULL);
-	admin_proxies = NULL;
+	g_list_free_full(set_proxies, NULL);
+	set_proxies = NULL;
+	g_list_free_full(status_proxies, NULL);
+	status_proxies = NULL;
 }
 
 void admin_add_submenu(void)
diff --git a/client/admin.h b/client/admin.h
index 0047770dc..be58fb2fa 100644
--- a/client/admin.h
+++ b/client/admin.h
@@ -10,3 +10,7 @@
 
 void admin_add_submenu(void);
 void admin_remove_submenu(void);
+
+GDBusProxy *bluetoothctl_get_default_controller(void);
+GDBusProxy *bluetoothctl_find_controller(const char *address);
+char *bluetoothctl_controller_generator(const char *text, int state);
diff --git a/client/main.c b/client/main.c
index 9d9ac8b14..5e9f2eeb5 100644
--- a/client/main.c
+++ b/client/main.c
@@ -881,6 +881,25 @@ static struct adapter *find_ctrl_by_address(GList *source, const char *address)
 	return NULL;
 }
 
+GDBusProxy *bluetoothctl_get_default_controller(void)
+{
+	if (!default_ctrl)
+		return NULL;
+
+	return default_ctrl->proxy;
+}
+
+GDBusProxy *bluetoothctl_find_controller(const char *address)
+{
+	struct adapter *adapter;
+
+	adapter = find_ctrl_by_address(ctrl_list, address);
+	if (!adapter)
+		return NULL;
+
+	return adapter->proxy;
+}
+
 static GDBusProxy *find_proxies_by_iface(GList *source, const char *path,
 							const char *iface)
 {
@@ -2788,7 +2807,7 @@ static char *generic_generator(const char *text, int state,
 	return NULL;
 }
 
-static char *ctrl_generator(const char *text, int state)
+char *bluetoothctl_controller_generator(const char *text, int state)
 {
 	static int index = 0;
 	static int len = 0;
@@ -3876,9 +3895,9 @@ static const struct bt_shell_menu main_menu = {
 	.entries = {
 	{ "list",         NULL,       cmd_list, "List available controllers" },
 	{ "show",         "[ctrl]",   cmd_show, "Controller information",
-							ctrl_generator },
+					bluetoothctl_controller_generator },
 	{ "select",       "<ctrl>",   cmd_select, "Select default controller",
-							ctrl_generator },
+					bluetoothctl_controller_generator },
 	{ "devices",      "[Paired/Bonded/Trusted/Connected]", cmd_devices,
 					"List available devices, with an "
 					"optional property as the filter" },
-- 
2.43.0


  reply	other threads:[~2026-07-02  8:36 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-02  8:36 [PATCH BlueZ 1/7] plugins/admin: make AdminPolicy state per-adapter Frédéric Danis
2026-07-02  8:36 ` Frédéric Danis [this message]
2026-07-02  8:36 ` [PATCH BlueZ 3/7] doc: document admin.allow optional controller argument Frédéric Danis
2026-07-02  8:36 ` [PATCH BlueZ 4/7] src/adapter: enforce allowlist for local services Frédéric Danis
2026-07-02  8:36 ` [PATCH BlueZ 5/7] plugins/admin: reapply allowlist on policy updates Frédéric Danis
2026-07-02  8:36 ` [PATCH BlueZ 6/7] doc: describe admin allowlist runtime enforcement Frédéric Danis
2026-07-02  8:36 ` [PATCH BlueZ 7/7] profiles/audio: fix UAF on external media service teardown Frédéric Danis
2026-07-02 11:57 ` [BlueZ,1/7] plugins/admin: make AdminPolicy state per-adapter bluez.test.bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260702083641.378994-2-frederic.danis@collabora.com \
    --to=frederic.danis@collabora.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.