Admin policy series
Subsystems (2)
v7 cover Admin policy series
From: Yun-Hao Chung <[email protected]>
Hi manintainers,
This series is to
1. Implement a few methods in core so that a plugin can have control of allowing / disallowing certain service connections.
2. Implement the AdminPolicy plugin. The plugin provides interfaces AdminPolicySet and AdminPolicyStatus. For each policy, users should set the value thorugh AdminPolicySet and query the current setting through AdminPolicyStatus. We separeted these two interfaces so that developers can assign different groups of users to these interfaces. Currently the only policy is ServiceAllowList, which make bluez only allow a list of service by specified their UUIDs, but the plugin is also expected to provide more controls over other bluez behaviors.
Since the second part is a plugin, it might not be necessary to land in upstream tree.
Thanks.
Changes in v7:
- Fix compiler errors in profiles/hdp.c
Changes in v6:
- include <errno.h> instead of <error.h> in plugins/admin.c
Changes in v5:
- Fix compiler errors in plugins/admin.c
Changes in v4:
- Update commit message (admin_policy -> admin)
- remove old plugins/admin_policy.c
Changes in v3:
- Rename plugins/admin_policy.c -> plugins/admin.c
- Use device_added callback in btd_adapter_driver instead of listen for dbus
- Add authorization method in profiles/health/mcap.c and block incoming connections in adapter authorization function.
Changes in v2:
- Move bt_uuid_hash and bt_uuid_equal functions to adapter.c.
- Modify the criteria to say a device is Affected from any-of-uuid to any-of-auto-connect-profile.
- Remove the code to remove/reprobe disallowed/allowed profiles, instead, check if the service is allowed in bt_io_accept connect_cb.
- Fix a typo in emit_property_change in plugin/admin_policy.c:set_service_allowlist
- Instead of using device_state_cb, utilize D-BUS client to watch device added/removed.
- Add a document in doc/
Yun-Hao Chung (13):
core: add is_allowed property in btd_service
core: add adapter and device allowed_uuid functions
mcap: add adapter authorization
core: block not allowed UUID connect in auth
core: add device_added and device_removed to adapter driver
plugins: new plugin
plugins/admin: add admin_policy adapter driver plugins/admin: add ServiceAllowList method plugins/admin: add ServiceAllowList property plugins/admin: add device callbacks plugins/admin: add AffectedByPolicy property plugins/admin: persist policy settings
doc: add description of admin policy
Makefile.plugins | 5 + android/health.c | 2 +- bootstrap-configure | 1 + configure.ac | 4 + doc/admin-policy-api.txt | 65 +++++ plugins/admin.c | 592 +++++++++++++++++++++++++++++++++++++++ profiles/health/hdp.c | 1 + profiles/health/mcap.c | 38 ++- profiles/health/mcap.h | 9 + src/adapter.c | 154 +++++++++- src/adapter.h | 12 + src/device.c | 64 ++++- src/device.h | 2 + src/profile.c | 11 + src/service.c | 39 +++ src/service.h | 2 + tools/mcaptest.c | 2 +- 17 files changed, 993 insertions(+), 10 deletions(-) create mode 100644 doc/admin-policy-api.txt create mode 100644 plugins/admin.c
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 1/13 core: add is_allowed property in btd_service
From: Yun-Hao Chung <[email protected]>
This adds is_allowed property in btd_service. When is_allowed is set to false, calling btd_service_connect and service_accept will fail and the existing service connection gets disconnected.
---
Changes in v7:
- Fix compiler errors in profiles/hdp.c
Changes in v6:
- include <errno.h> instead of <error.h> in plugins/admin.c
Changes in v5:
- Fix compiler errors in plugins/admin.c
Changes in v4:
- Update commit message (admin_policy -> admin)
- remove old plugins/admin_policy.c
Changes in v3:
- Rename plugins/admin_policy.c -> plugins/admin.c
- Use device_added callback in btd_adapter_driver instead of listen for dbus
- Add authorization method in profiles/health/mcap.c and block incoming connections in adapter authorization function.
Changes in v2:
- Move bt_uuid_hash and bt_uuid_equal functions to adapter.c.
- Modify the criteria to say a device is Affected from any-of-uuid to any-of-auto-connect-profile.
- Remove the code to remove/reprobe disallowed/allowed profiles, instead, check if the service is allowed in bt_io_accept connect_cb.
- Fix a typo in emit_property_change in plugin/admin_policy.c:set_service_allowlist
- Instead of using device_state_cb, utilize D-BUS client to watch device added/removed.
- Add a document in doc/
src/service.c | 39 +++++++++++++++++++++++++++++++++++++++ src/service.h | 2 ++ 2 files changed, 41 insertions(+)
src/service.c +39 -0
@@ -41,6 +41,7 @@ struct btd_service {void *user_data;btd_service_state_t state;int err; +bool is_allowed; };struct service_state_callback {
@@ -133,6 +134,7 @@ struct btd_service *service_create(struct btd_device *device, service->device = device;/* Weak ref */ service->profile = profile; service->state =BTD_SERVICE_STATE_UNAVAILABLE ; + service->is_allowed = true;return service; }
@@ -186,6 +188,18 @@ int service_accept(struct btd_service *service)if (!service->profile->accept)return -ENOSYS ; +if (!service->is_allowed) { +info ("service %s is not allowed" , + service->profile->remote_uuid); +return -ECONNABORTED ; + } + +if (!service->is_allowed) { +info ("service %s is not allowed" , + service->profile->remote_uuid); +return -ECONNABORTED ; + } + err = service->profile->accept (service);if (!err) goto done;
@@ -245,6 +259,12 @@ int btd_service_connect(struct btd_service *service)return -EBUSY ; } +if (!service->is_allowed) { +info ("service %s is not allowed" , + service->profile->remote_uuid); +return -ECONNABORTED ; + } + err = profile->connect (service);if (err ==0 ) {change_state (service,BTD_SERVICE_STATE_CONNECTING ,0 );
@@ -361,6 +381,25 @@ bool btd_service_remove_state_cb(unsigned int id)return false; } +void btd_service_set_allowed (struct btd_service *service,bool allowed) +{ +if (allowed == service->is_allowed) +return ; + + service->is_allowed = allowed; + +if (!allowed && (service->state ==BTD_SERVICE_STATE_CONNECTING || + service->state ==BTD_SERVICE_STATE_CONNECTED )) { +btd_service_disconnect (service); +return ; + } +} + +bool btd_service_is_allowed (struct btd_service *service) +{ +return service->is_allowed; +} +void btd_service_connecting_complete (struct btd_service *service,int err) { if (service->state != BTD_SERVICE_STATE_DISCONNECTED &&
src/service.h +2 -0
@@ -51,6 +51,8 @@ int btd_service_get_error(const struct btd_service *service);unsigned int btd_service_add_state_cb (btd_service_state_cb cb,void *user_data);bool btd_service_remove_state_cb (unsigned int id); +void btd_service_set_allowed (struct btd_service *service,bool allowed); +bool btd_service_is_allowed (struct btd_service *service);/* Functions used by profile implementation */ void btd_service_connecting_complete (struct btd_service *service,int err);
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=524779
---Test result---
Test Summary:
CheckPatch FAIL 5.01 seconds GitLint PASS 1.80 seconds Prep - Setup ELL PASS 51.29 seconds Build - Prep PASS 0.15 seconds Build - Configure PASS 9.29 seconds Build - Make PASS 230.56 seconds Make Check PASS 9.10 seconds Make Distcheck PASS 268.60 seconds Build w/ext ELL - Configure PASS 9.11 seconds Build w/ext ELL - Make PASS 220.09 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script with rule in .checkpatch.conf Output:
mcap: add adapter authorization
WARNING:NEW_TYPEDEFS: do not add new typedefs
#160: FILE: profiles/health/mcap.h:255:
+typedef guint (* mcap_authorize_cb) (const bdaddr_t *src, const bdaddr_t *dst,
WARNING:LONG_LINE_COMMENT: line length of 93 exceeds 80 columns #171: FILE: profiles/health/mcap.h:281:
+ mcap_authorize_cb authorize_cb; /* Method to request authorization */
- total: 0 errors, 2 warnings, 148 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
"[PATCH] mcap: add adapter authorization" has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
core: add device_added and device_removed to adapter driver WARNING:SPACING: Unnecessary space before function pointer arguments #130: FILE: src/adapter.h:114:
+ void (*device_added) (struct btd_adapter *adapter,
WARNING:SPACING: Unnecessary space before function pointer arguments #132: FILE: src/adapter.h:116:
+ void (*device_removed) (struct btd_adapter *adapter,
- total: 0 errors, 2 warnings, 112 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
"[PATCH] core: add device_added and device_removed to adapter driver" has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
plugins/admin: add ServiceAllowList property ERROR:SPACING: need consistent spacing around '*' (ctx:WxV) #63: FILE: plugins/admin.c:186:
+ const GDBusPropertyTable *property,
^
- total: 1 errors, 0 warnings, 82 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
"[PATCH] plugins/admin: add ServiceAllowList property" has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
plugins/admin: add AffectedByPolicy property ERROR:SPACING: need consistent spacing around '*' (ctx:WxV) #65: FILE: plugins/admin.c:254:
+ const GDBusPropertyTable *property,
^
- total: 1 errors, 0 warnings, 120 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
"[PATCH] plugins/admin: add AffectedByPolicy property" has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
plugins/admin: persist policy settings WARNING:LINE_SPACING: Missing a blank line after declarations #164: FILE: plugins/admin.c:340:
+ struct queue *uuid_list = NULL;
+ gchar **uuids = NULL;
- total: 0 errors, 1 warnings, 216 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
"[PATCH] plugins/admin: persist policy settings" has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: GitLint - PASS
Desc: Run gitlint with rule in .gitlint
##############################
Test: Prep - Setup ELL - PASS
Desc: Clone, build, and install ELL
##############################
Test: Build - Prep - PASS
Desc: Prepare environment for build
##############################
Test: Build - Configure - PASS
Desc: Configure the BlueZ source tree
##############################
Test: Build - Make - PASS
Desc: Build the BlueZ source tree
##############################
Test: Make Check - PASS
Desc: Run 'make check'
##############################
Test: Make Distcheck - PASS
Desc: Run distcheck to check the distribution
##############################
Test: Build w/ext ELL - Configure - PASS
Desc: Configure BlueZ source with '--enable-external-ell' configuration
##############################
Test: Build w/ext ELL - Make - PASS
Desc: Build BlueZ source with '--enable-external-ell' configuration
---
Regards,
Linux Bluetooth
PATCH v7 2/13 core: add adapter and device allowed_uuid functions
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This implements functions in src/adapter.c and src/device.c for plugins setting a list of allowed services.
---
(no changes since v1)
src/adapter.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/adapter.h | 8 +++++ src/device.c | 64 +++++++++++++++++++++++++++++++++++- src/device.h | 2 ++ 4 files changed, 163 insertions(+), 1 deletion(-)
src/adapter.c +90 -0
@@ -260,6 +260,8 @@ struct btd_adapter {struct btd_battery_provider_manager *battery_provider_manager; +GHashTable *allowed_uuid_set;/* Set of allowed service UUIDs */ +gboolean initialized;GSList *pin_callbacks;
@@ -3489,6 +3491,93 @@ static DBusMessage *connect_device(DBusConnection *conn,return NULL ; } +static void update_device_allowed_services (void *data,void *user_data) +{ +struct btd_device *device = data; + +btd_device_update_allowed_services (device); +} + +static void add_uuid_to_uuid_set (void *data,void *user_data) +{ +bt_uuid_t *uuid = data; +GHashTable *uuid_set = user_data; + +if (!uuid) { +error ("Found NULL in UUID allowed list" ); +return ; + } + +g_hash_table_add (uuid_set, uuid); +} + +static guint bt_uuid_hash (gconstpointer key) +{ +const bt_uuid_t *uuid = key; +bt_uuid_t uuid_128; +uint64_t *val; + +if (!uuid) +return 0 ; + +bt_uuid_to_uuid128 (uuid, &uuid_128); + val = (uint64_t *)&uuid_128.value.u128; + +return g_int64_hash (val) ^g_int64_hash (val+1 ); +} + +static gboolean bt_uuid_equal (gconstpointer v1,gconstpointer v2) +{ +const bt_uuid_t *uuid1 = v1; +const bt_uuid_t *uuid2 = v2; + +if (!uuid1 || !uuid2) +return !uuid1 && !uuid2; + +return bt_uuid_cmp (uuid1, uuid2) ==0 ; +} + +bool btd_adapter_set_allowed_uuids (struct btd_adapter *adapter, +struct queue *uuids) +{ +if (!adapter) +return false; + +if (adapter->allowed_uuid_set) +g_hash_table_destroy (adapter->allowed_uuid_set); + + adapter->allowed_uuid_set =g_hash_table_new (bt_uuid_hash, + bt_uuid_equal); +if (!adapter->allowed_uuid_set) { +btd_error (adapter->dev_id, +"Failed to allocate allowed_uuid_set" ); +return false; + } + +queue_foreach (uuids, add_uuid_to_uuid_set, adapter->allowed_uuid_set); +g_slist_foreach (adapter->devices, update_device_allowed_services,NULL ); + +return true; +} + +bool btd_adapter_is_uuid_allowed (struct btd_adapter *adapter, +const char *uuid_str) +{ +bt_uuid_t uuid; + +if (!adapter || !adapter->allowed_uuid_set) +return true; + +if (bt_string_to_uuid (&uuid, uuid_str)) { +btd_error (adapter->dev_id, +"Failed to parse UUID string '%s'" , uuid_str); +return false; + } + +return !g_hash_table_size (adapter->allowed_uuid_set) || +g_hash_table_contains (adapter->allowed_uuid_set, &uuid); +} +static const GDBusMethodTable adapter_methods[] = { {GDBUS_ASYNC_METHOD ("StartDiscovery" ,NULL ,NULL , start_discovery) }, { GDBUS_METHOD("SetDiscoveryFilter",
@@ -5404,6 +5493,7 @@ static void adapter_free(gpointer user_data)g_free (adapter->stored_alias);g_free (adapter->current_alias);free (adapter->modalias); +g_hash_table_destroy (adapter->allowed_uuid_set);g_free (adapter); }
src/adapter.h +8 -0
@@ -25,6 +25,7 @@struct btd_adapter ;struct btd_device ; +struct queue ;struct btd_adapter *btd_adapter_get_default (void );bool btd_adapter_is_default (struct btd_adapter *adapter);
@@ -97,6 +98,8 @@ void adapter_service_remove(struct btd_adapter *adapter, uint32_t handle);struct agent *adapter_get_agent (struct btd_adapter *adapter); +bool btd_adapter_uuid_is_allowed (struct btd_adapter *adapter,const char *uuid); +struct btd_adapter *btd_adapter_ref (struct btd_adapter *adapter);void btd_adapter_unref (struct btd_adapter *adapter);
@@ -240,3 +243,8 @@ enum kernel_features { };bool btd_has_kernel_features (uint32_t feature); + +bool btd_adapter_set_allowed_uuids (struct btd_adapter *adapter, +struct queue *uuids); +bool btd_adapter_is_uuid_allowed (struct btd_adapter *adapter, +const char *uuid_str);
src/device.c +63 -1
90 lines not on this page · raw message
src/device.h +2 -0
@@ -175,5 +175,7 @@ uint32_t btd_device_get_current_flags(struct btd_device *dev);void btd_device_flags_changed (struct btd_device *dev,uint32_t supported_flags,uint32_t current_flags); +bool btd_device_all_services_allowed (struct btd_device *dev); +void btd_device_update_allowed_services (struct btd_device *dev);void btd_device_init (void );void btd_device_cleanup (void );
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 3/13 mcap: add adapter authorization
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
Currently mcap is the only profile that doesn't request adatper authorization. This patch adds a argument when creating the mcap instance to set authorize method. The reason why we don't use btd_request_authorization directly like all other profiles is because tools/mcaptest includes the profile/health/mcap.h. If we add dependency to adapter.h in mcap.h, it will make mcaptest depend on adapter and be not able to build independently.
---
(no changes since v1)
android/health.c | 2 +- profiles/health/hdp.c | 1 + profiles/health/mcap.c | 38 ++++++++++++++++++++++++++++++++++++-- profiles/health/mcap.h | 9 +++++++++ tools/mcaptest.c | 2 +- 5 files changed, 48 insertions(+), 4 deletions(-)
android/health.c +1 -1
@@ -2008,7 +2008,7 @@ bool bt_health_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode) mcl_connected, mcl_reconnected, mcl_disconnected, mcl_uncached,NULL ,/* CSP is not used right now */ - NULL, &err); + NULL, NULL, &err);if (!mcap) {error ("health: MCAP instance creation failed %s" , err->message);g_error_free (err);
profiles/health/hdp.c +1 -0
@@ -1347,6 +1347,7 @@ static gboolean update_adapter(struct hdp_adapter *hdp_adapter) mcl_connected, mcl_reconnected, mcl_disconnected, mcl_uncached,NULL ,/* CSP is not used by now */ + btd_request_authorization, hdp_adapter, &err);if (hdp_adapter->mi ==NULL ) {error ("Error creating the MCAP instance: %s" , err->message);
profiles/health/mcap.c +36 -2
@@ -14,6 +14,7 @@#endif #define _GNU_SOURCE +#include <dbus/dbus.h> #include <netinet/in.h> #include <stdlib.h> #include <errno.h>
@@ -23,6 +24,7 @@#include <glib.h> #include "lib/bluetooth.h" +#include "lib/uuid.h" #include "bluetooth/l2cap.h" #include "btio/btio.h" #include "src/log.h"
@@ -1980,7 +1982,6 @@ static void set_mcl_conf(GIOChannel *chan, struct mcap_mcl *mcl) mcl->state =MCL_CONNECTED ; mcl->role =MCL_ACCEPTOR ; mcl->req =MCL_AVAILABLE ; - mcl->cc =g_io_channel_ref (chan); mcl->ctrl |=MCAP_CTRL_STD_OP ;mcap_sync_init (mcl);
@@ -2005,19 +2006,38 @@ static void set_mcl_conf(GIOChannel *chan, struct mcap_mcl *mcl) mcl->mi->mcl_connected_cb (mcl, mcl->mi->user_data); } +static void auth_callback (DBusError *derr,void *user_data) +{ +struct mcap_mcl *mcl = user_data; + +if (derr) { +error ("Access denied: %s" , derr->message); + goto reject; + } + +set_mcl_conf (mcl->cc, mcl); +return ; + +reject: +g_io_channel_shutdown (mcl->cc, TRUE,NULL ); +g_io_channel_unref (mcl->cc); +} +static void connect_mcl_event_cb (GIOChannel *chan,GError *gerr,gpointer user_data) {struct mcap_instance *mi = user_data;struct mcap_mcl *mcl; -bdaddr_t dst; +bdaddr_t src, dst;char address[18 ], srcstr[18 ];GError *err =NULL ; +guint ret;if (gerr)return ;bt_io_get (chan, &err, +BT_IO_OPT_SOURCE_BDADDR , &src,BT_IO_OPT_DEST_BDADDR , &dst,BT_IO_OPT_DEST , address,BT_IO_OPT_INVALID );
@@ -2044,6 +2064,18 @@ static void connect_mcl_event_cb(GIOChannel *chan, GError *gerr, mcl->next_mdl = (rand () %MCAP_MDLID_FINAL ) +1 ; } + mcl->cc =g_io_channel_ref (chan); +if (mi->authorize_cb) { + ret = mi->authorize_cb (&src, &dst,HDP_UUID , auth_callback, + mcl); +if (ret !=0 ) +return ; + +error ("HDP: authorization for device %s failed" , address); +g_io_channel_unref (mcl->cc); + goto drop; + } +set_mcl_conf (chan, mcl);return ;
@@ -2060,6 +2092,7 @@ struct mcap_instance *mcap_create_instance(const bdaddr_t *src,mcap_mcl_event_cb mcl_disconnected, mcap_mcl_event_cb mcl_uncached, mcap_info_ind_event_cb mcl_sync_info_ind, + mcap_authorize_cb authorize_cb, gpointer user_data, GError **gerr) {
@@ -2089,6 +2122,7 @@ struct mcap_instance *mcap_create_instance(const bdaddr_t *src, mi->mcl_disconnected_cb = mcl_disconnected; mi->mcl_uncached_cb = mcl_uncached; mi->mcl_sync_infoind_cb = mcl_sync_info_ind; + mi->authorize_cb = authorize_cb; mi->user_data = user_data; mi->csp_enabled = FALSE;
profiles/health/mcap.h +9 -0
@@ -9,6 +9,8 @@* */ +#include <dbus/dbus.h> +#define MCAP_VERSION 0x0100/* current version 01.00 */ /* bytes to get MCAP Supported Procedures */
@@ -249,6 +251,11 @@ typedef void (* mcap_sync_set_cb) (struct mcap_mcl *mcl,GError *err, gpointer data); +typedef void mcap_auth_cb (DBusError *derr,void *user_data); +typedef guint (*mcap_authorize_cb ) (const bdaddr_t *src,const bdaddr_t *dst, +const char *uuid,mcap_auth_cb cb, +void *user_data); +struct mcap_mdl_cb {mcap_mdl_event_cb mdl_connected;/* Remote device has created a MDL */ mcap_mdl_event_cb mdl_closed;/* Remote device has closed a MDL */
@@ -271,6 +278,7 @@ struct mcap_instance {mcap_mcl_event_cb mcl_disconnected_cb;/* MCL disconnected */ mcap_mcl_event_cb mcl_uncached_cb;/* MCL has been removed from MCAP cache */ mcap_info_ind_event_cb mcl_sync_infoind_cb;/* (CSP Master) Received info indication */ +mcap_authorize_cb authorize_cb;/* Method to request authorization */ gpointer user_data;/* Data to be provided in callbacks */ int ref;/* Reference counter */
@@ -404,6 +412,7 @@ struct mcap_instance *mcap_create_instance(const bdaddr_t *src,mcap_mcl_event_cb mcl_disconnected, mcap_mcl_event_cb mcl_uncached, mcap_info_ind_event_cb mcl_sync_info_ind, + mcap_authorize_cb authorize_cb, gpointer user_data, GError **gerr);void mcap_release_instance (struct mcap_instance *mi);
tools/mcaptest.c +1 -1
@@ -434,7 +434,7 @@ int main(int argc, char *argv[]) mcl_connected, mcl_reconnected, mcl_disconnected, mcl_uncached,NULL ,/* CSP is not used right now */ - NULL, &err); + NULL, NULL, &err);if (!mcap) {printf ("MCAP instance creation failed %s\n" , err->message);
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
Luiz Augusto von Dentz
maintainerRe: [Bluez PATCH v7 03/13] mcap: add adapter authorization
Hi Howard,
Quoted 154 lines · Howard Chung
From: Yun-Hao Chung <[email protected]>
Currently mcap is the only profile that doesn't request adatper authorization. This patch adds a argument when creating the mcap instance to set authorize method. The reason why we don't use
btd_request_authorizationdirectly like all other profiles is becausetools/mcaptestincludes theprofile/health/mcap.h. If we add dependency toadapter.hinmcap.h, it will make mcaptest depend on adapter and be not able to build independently.
---(no changes since v1)
android/health.c | 2 +- profiles/health/hdp.c | 1 + profiles/health/mcap.c | 38 ++++++++++++++++++++++++++++++++++++-- profiles/health/mcap.h | 9 +++++++++ tools/mcaptest.c | 2 +- 5 files changed, 48 insertions(+), 4 deletions(-)android/health.c +1
-1@@ -2008,7 +2008,7 @@ bool bt_health_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode) mcl_connected, mcl_reconnected, mcl_disconnected, mcl_uncached,NULL ,/* CSP is not used right now */ - NULL, &err); + NULL, NULL, &err);if (!mcap) {error ("health: MCAP instance creation failed %s" , err->message);g_error_free (err);profiles/health/hdp.c +1
-0@@ -1347,6 +1347,7 @@ static gboolean update_adapter(struct hdp_adapter *hdp_adapter) mcl_connected, mcl_reconnected, mcl_disconnected, mcl_uncached,NULL ,/* CSP is not used by now */ + btd_request_authorization, hdp_adapter, &err);if (hdp_adapter->mi ==NULL ) {error ("Error creating the MCAP instance: %s" , err->message);profiles/health/mcap.c +36
-2@@ -14,6 +14,7 @@#endif #define _GNU_SOURCE +#include <dbus/dbus.h> #include <netinet/in.h> #include <stdlib.h> #include <errno.h> @@ -23,6 +24,7 @@#include <glib.h> #include "lib/bluetooth.h" +#include "lib/uuid.h" #include "bluetooth/l2cap.h" #include "btio/btio.h" #include "src/log.h" @@ -1980,7 +1982,6 @@ static void set_mcl_conf(GIOChannel *chan, struct mcap_mcl *mcl) mcl->state =MCL_CONNECTED ; mcl->role =MCL_ACCEPTOR ; mcl->req =MCL_AVAILABLE ; - mcl->cc =g_io_channel_ref (chan); mcl->ctrl |=MCAP_CTRL_STD_OP ;mcap_sync_init (mcl);@@ -2005,19 +2006,38 @@ static void set_mcl_conf(GIOChannel *chan, struct mcap_mcl *mcl) mcl->mi->mcl_connected_cb (mcl, mcl->mi->user_data); } +static void auth_callback (DBusError *derr,void *user_data) +{ +struct mcap_mcl *mcl = user_data; + +if (derr) { +error ("Access denied: %s" , derr->message); + goto reject; + } + +set_mcl_conf (mcl->cc, mcl); +return ; + +reject: +g_io_channel_shutdown (mcl->cc, TRUE,NULL ); +g_io_channel_unref (mcl->cc); +} +static void connect_mcl_event_cb (GIOChannel *chan,GError *gerr,gpointer user_data) {struct mcap_instance *mi = user_data;struct mcap_mcl *mcl; -bdaddr_t dst; +bdaddr_t src, dst;char address[18 ], srcstr[18 ];GError *err =NULL ; +guint ret;if (gerr)return ;bt_io_get (chan, &err, +BT_IO_OPT_SOURCE_BDADDR , &src,BT_IO_OPT_DEST_BDADDR , &dst,BT_IO_OPT_DEST , address,BT_IO_OPT_INVALID );@@ -2044,6 +2064,18 @@ static void connect_mcl_event_cb(GIOChannel *chan, GError *gerr, mcl->next_mdl = (rand () %MCAP_MDLID_FINAL ) +1 ; } + mcl->cc =g_io_channel_ref (chan); +if (mi->authorize_cb) { + ret = mi->authorize_cb (&src, &dst,HDP_UUID , auth_callback, + mcl); +if (ret !=0 ) +return ; + +error ("HDP: authorization for device %s failed" , address); +g_io_channel_unref (mcl->cc); + goto drop; + } +set_mcl_conf (chan, mcl);return ;@@ -2060,6 +2092,7 @@ struct mcap_instance *mcap_create_instance(const bdaddr_t *src,mcap_mcl_event_cb mcl_disconnected, mcap_mcl_event_cb mcl_uncached, mcap_info_ind_event_cb mcl_sync_info_ind, + mcap_authorize_cb authorize_cb, gpointer user_data, GError **gerr) {@@ -2089,6 +2122,7 @@ struct mcap_instance *mcap_create_instance(const bdaddr_t *src, mi->mcl_disconnected_cb = mcl_disconnected; mi->mcl_uncached_cb = mcl_uncached; mi->mcl_sync_infoind_cb = mcl_sync_info_ind; + mi->authorize_cb = authorize_cb; mi->user_data = user_data; mi->csp_enabled = FALSE;profiles/health/mcap.h +0
-0
profiles/health/mcap.h line 10
Quoted 2 lines
profiles/health/mcap.h +0
-0@@ -9,6 +9,8 @@* */
These changes to mcap.h are causing a lot problems with CI, it seems the comments are not going over 80 columns so if you really need to touch this file you might as well move the comments above each field, or perhaps don't bother changing the health plugin since it is normally not enabled by default and we might as well consider it deprecated given that has been many years without maintenance and afaik these profiles have been moved to LE at some point.
Quoted 49 lines
profiles/health/mcap.h +9
-0+#include <dbus/dbus.h> +#define MCAP_VERSION 0x0100/* current version 01.00 */ /* bytes to get MCAP Supported Procedures */ @@ -249,6 +251,11 @@ typedef void (* mcap_sync_set_cb) (struct mcap_mcl *mcl,GError *err, gpointer data); +typedef void mcap_auth_cb (DBusError *derr,void *user_data); +typedef guint (*mcap_authorize_cb ) (const bdaddr_t *src,const bdaddr_t *dst, +const char *uuid,mcap_auth_cb cb, +void *user_data); +struct mcap_mdl_cb {mcap_mdl_event_cb mdl_connected;/* Remote device has created a MDL */ mcap_mdl_event_cb mdl_closed;/* Remote device has closed a MDL */ @@ -271,6 +278,7 @@ struct mcap_instance {mcap_mcl_event_cb mcl_disconnected_cb;/* MCL disconnected */ mcap_mcl_event_cb mcl_uncached_cb;/* MCL has been removed from MCAP cache */ mcap_info_ind_event_cb mcl_sync_infoind_cb;/* (CSP Master) Received info indication */ +mcap_authorize_cb authorize_cb;/* Method to request authorization */ gpointer user_data;/* Data to be provided in callbacks */ int ref;/* Reference counter */ @@ -404,6 +412,7 @@ struct mcap_instance *mcap_create_instance(const bdaddr_t *src,mcap_mcl_event_cb mcl_disconnected, mcap_mcl_event_cb mcl_uncached, mcap_info_ind_event_cb mcl_sync_info_ind, + mcap_authorize_cb authorize_cb, gpointer user_data, GError **gerr);void mcap_release_instance (struct mcap_instance *mi);tools/mcaptest.c +1
-2@@ -434,7 +434,7 @@ int main(int argc, char *argv[]) mcl_connected, mcl_reconnected, mcl_disconnected, mcl_uncached,NULL ,/* CSP is not used right now */ - NULL, &err); + NULL, NULL, &err);if (!mcap) {printf ("MCAP instance creation failed %s\n" , err->message); --2.32.0.554.ge1b32706d8-goog
Signature · 1 line
Luiz Augusto von Dentz
PATCH v7 4/13 core: block not allowed UUID connect in auth
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This ensures any incoming profile connection will be blocked if its UUID is not allowed by the following assumption:
1. Each system profile asks adapter authorization when seeing a incoming connection.
2. Each external profile checks if its UUID is allowed by adapter when seeing a incoming connection.
---
The following test steps were performed after enabling admin plugin:
1. Set ServiceAllowList to ["1234"].
2. Turn on a paired classic keyboard. Verify it can not be connected.
3. Set ServiceAllowList to ["1800","1801","180A","180F","1812"]
4. Turn off and turn on the keyboard. Verift it can be connected.
(no changes since v1)
src/adapter.c | 5 +++++ src/profile.c | 11 +++++++++++ 2 files changed, 16 insertions(+)
src/adapter.c +5 -0
@@ -7118,6 +7118,11 @@ static gboolean process_auth_queue(gpointer user_data)if (auth->svc_id >0 )return FALSE; +if (!btd_adapter_is_uuid_allowed (adapter, auth->uuid)) { + auth->cb (&err, auth->user_data); + goto next; + } +if (device_is_trusted (device) == TRUE) { auth->cb (NULL , auth->user_data); goto next;
src/profile.c +11 -0
@@ -1249,6 +1249,11 @@ static void ext_confirm(GIOChannel *io, gpointer user_data)DBG ("incoming connect from %s" , addr); +if (!btd_adapter_is_uuid_allowed (adapter_find (&src), uuid)) { +info ("UUID %s is not allowed. Igoring the connection" , uuid); +return ; + } + conn =create_conn (server, io, &src, &dst);if (conn ==NULL )return ;
@@ -1272,6 +1277,7 @@ static void ext_direct_connect(GIOChannel *io, GError *err, gpointer user_data)struct ext_profile *ext = server->ext;GError *gerr =NULL ;struct ext_io *conn; +const char *uuid = ext->service ? ext->service : ext->uuid;bdaddr_t src, dst; bt_io_get(io, &gerr,
@@ -1285,6 +1291,11 @@ static void ext_direct_connect(GIOChannel *io, GError *err, gpointer user_data)return ; } +if (!btd_adapter_is_uuid_allowed (adapter_find (&src), uuid)) { +info ("UUID %s is not allowed. Igoring the connection" , uuid); +return ; + } + conn =create_conn (server, io, &src, &dst);if (conn ==NULL )return ;
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 5/13 core: add device_added and device_removed to adapter driver
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This adds device_added and device_removed to btd_adapter_driver so that a driver can get notification when device is added or removed.
---
(no changes since v1)
src/adapter.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++----- src/adapter.h | 4 ++++ 2 files changed, 58 insertions(+), 5 deletions(-)
src/adapter.c +54 -5
@@ -1218,6 +1218,9 @@ void adapter_service_remove(struct btd_adapter *adapter, uint32_t handle)remove_record_from_server (rec->handle); } +static void adapter_add_device (struct btd_adapter *adapter, +struct btd_device *device); +static struct btd_device *adapter_create_device (struct btd_adapter *adapter,const bdaddr_t *bdaddr,uint8_t bdaddr_type)
@@ -1228,8 +1231,7 @@ static struct btd_device *adapter_create_device(struct btd_adapter *adapter,if (!device)return NULL ; - adapter->devices =g_slist_append (adapter->devices, device); - +adapter_add_device (adapter, device);return device; }
@@ -1256,6 +1258,9 @@ static void service_auth_cancel(struct service_auth *auth)g_free (auth); } +static void adapter_remove_device (struct btd_adapter *adapter, +struct btd_device *device); +void btd_adapter_remove_device (struct btd_adapter *adapter,struct btd_device *dev) {
@@ -1263,7 +1268,7 @@ void btd_adapter_remove_device(struct btd_adapter *adapter, adapter->connect_list =g_slist_remove (adapter->connect_list, dev); - adapter->devices =g_slist_remove (adapter->devices, dev); +adapter_remove_device (adapter, dev);btd_adv_monitor_device_remove (adapter->adv_monitor_manager, dev); adapter->discovery_found = g_slist_remove(adapter->discovery_found,
@@ -4665,7 +4670,7 @@ static void load_devices(struct btd_adapter *adapter) goto free;btd_device_set_temporary (device, false); - adapter->devices =g_slist_append (adapter->devices, device); +adapter_add_device (adapter, device);/* TODO: register services from pre-loaded list of primaries */
@@ -4827,6 +4832,48 @@ void adapter_remove_profile(struct btd_adapter *adapter, gpointer p) profile->adapter_remove (profile, adapter); } +static void device_added_drivers (struct btd_adapter *adapter, +struct btd_device *device) +{ +struct btd_adapter_driver *driver; +GSList *l; + +for (l = adapter_drivers; l; l = l->next) { + driver = l->data; + +if (driver->device_added) + driver->device_added (adapter, device); + } +} + +static void device_removed_drivers (struct btd_adapter *adapter, +struct btd_device *device) +{ +struct btd_adapter_driver *driver; +GSList *l; + +for (l = adapter_drivers; l; l = l->next) { + driver = l->data; + +if (driver->device_removed) + driver->device_removed (adapter, device); + } +} + +static void adapter_add_device (struct btd_adapter *adapter, +struct btd_device *device) +{ + adapter->devices =g_slist_append (adapter->devices, device); +device_added_drivers (adapter, device); +} + +static void adapter_remove_device (struct btd_adapter *adapter, +struct btd_device *device) +{ + adapter->devices =g_slist_remove (adapter->devices, device); +device_removed_drivers (adapter, device); +} +static void adapter_add_connection (struct btd_adapter *adapter,struct btd_device *device,uint8_t bdaddr_type)
@@ -6445,8 +6492,10 @@ static void adapter_remove(struct btd_adapter *adapter)g_slist_free (adapter->connect_list); adapter->connect_list =NULL ; -for (l = adapter->devices; l; l = l->next) +for (l = adapter->devices; l; l = l->next) { +device_removed_drivers (adapter, l->data);device_remove (l->data, FALSE); + }g_slist_free (adapter->devices); adapter->devices =NULL ;
src/adapter.h +4 -0
@@ -111,6 +111,10 @@ struct btd_adapter_driver {int (*probe) (struct btd_adapter *adapter);void (*remove) (struct btd_adapter *adapter);void (*resume) (struct btd_adapter *adapter); +void (*device_added) (struct btd_adapter *adapter, +struct btd_device *device); +void (*device_removed) (struct btd_adapter *adapter, +struct btd_device *device); };typedef void (*service_auth_cb ) (DBusError *derr,void *user_data);
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 6/13 plugins: new plugin
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This adds an initial code for a new plugin admin.
---
(no changes since v1)
Makefile.plugins | 5 +++++ bootstrap-configure | 1 + configure.ac | 4 ++++ plugins/admin.c | 30 ++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 plugins/admin.c
Makefile.plugins +5 -0
@@ -11,6 +11,11 @@ builtin_sources += plugins/autopair.c builtin_modules += policy builtin_sources += plugins/policy.c +if ADMIN +builtin_modules += admin +builtin_sources += plugins/admin.c +endif + if NFC builtin_modules += neard builtin_sources += plugins/neard.c
bootstrap-configure +1 -0
@@ -30,4 +30,5 @@ fi --enable-pie \ --enable-cups \ --enable-library \ + --enable-admin \ --disable-datafiles $*
configure.ac +4 -0
@@ -364,6 +364,10 @@ AC_ARG_ENABLE(logger, AC_HELP_STRING([--enable-logger], [enable HCI logger service]), [enable_logger=${enableval}]) AM_CONDITIONAL(LOGGER, test "${enable_logger}" = "yes") +AC_ARG_ENABLE(admin, AC_HELP_STRING([--enable-admin], + [enable admin policy plugin]), [enable_admin=${enableval}]) +AM_CONDITIONAL(ADMIN, test "${enable_admin}" = "yes") + if (test "${prefix}" = "NONE"); then dnl no prefix and no localstatedir, so default to /var if (test "$localstatedir" = '${prefix}/var'); then
plugins/admin.c new file +30 -0
@@ -0,0 +1,30 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* +* +* BlueZ - Bluetooth protocol stack for Linux +* +* Copyright (C) 2021 Google LLC +* +* +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "src/log.h" +#include "src/plugin.h" + +static int admin_init (void ) +{ +DBG ("" ); +} + +static void admin_exit (void ) +{ +DBG ("" ); +} + +BLUETOOTH_PLUGIN_DEFINE (admin,VERSION , +BLUETOOTH_PLUGIN_PRIORITY_DEFAULT , + admin_init, admin_exit)
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 7/13 plugins/admin: add admin_policy adapter driver
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This adds code to register admin_policy driver to adapter when admin plugin is enabled.
The following test steps were performed:
1. restart bluetoothd
2. check if "Admin Policy is enabled" in system log
---
(no changes since v1)
plugins/admin.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+)
plugins/admin.c +67 -0
@@ -12,17 +12,84 @@#include <config.h> #endif +#include "lib/bluetooth.h" + +#include "src/adapter.h" +#include "src/error.h" #include "src/log.h" #include "src/plugin.h" +#include "src/shared/queue.h" + +/* |policy_data| has the same life cycle as btd_adapter */ +static struct btd_admin_policy { +struct btd_adapter *adapter; +uint16_t adapter_id; +} *policy_data =NULL ; + +static struct btd_admin_policy *admin_policy_new (struct btd_adapter *adapter) +{ +struct btd_admin_policy *admin_policy =NULL ; + + admin_policy =g_try_malloc (sizeof (*admin_policy)); +if (!admin_policy) { +btd_error (btd_adapter_get_index (adapter), +"Failed to allocate memory for admin_policy" ); +return NULL ; + } + + admin_policy->adapter = adapter; + admin_policy->adapter_id =btd_adapter_get_index (adapter); + +return admin_policy; +} + +static void admin_policy_free (void *data) +{ +struct btd_admin_policy *admin_policy = data; + +g_free (admin_policy); +} + +static int admin_policy_adapter_probe (struct btd_adapter *adapter) +{ +if (policy_data) { +btd_warn (policy_data->adapter_id, +"Policy data already exists" ); +admin_policy_free (policy_data); + policy_data =NULL ; + } + + policy_data =admin_policy_new (adapter); +if (!policy_data) +return -ENOMEM ; + +btd_info (policy_data->adapter_id,"Admin Policy has been enabled" ); + +return 0 ; +} + +static struct btd_adapter_driver admin_policy_driver = { + .name ="admin_policy" , + .probe = admin_policy_adapter_probe, + .resume =NULL , +}; +static int admin_init (void ) {DBG ("" ); + +return btd_register_adapter_driver (&admin_policy_driver); }static void admin_exit (void ) {DBG ("" ); + +btd_unregister_adapter_driver (&admin_policy_driver); + +if (policy_data) +admin_policy_free (policy_data); } BLUETOOTH_PLUGIN_DEFINE(admin, VERSION,
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 8/13 plugins/admin: add ServiceAllowList method
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This adds code to register interface org.bluez.AdminPolicySet1. The interface will provide methods to limit users to operate certain functions of bluez, such as allow/disallow user to taggle adapter power, or only allow users to connect services in the specified list, etc.
This patch also implements ServiceAllowlist in
org.bluez.AdminPolicySet1.
---
The following test steps were performed:
1. Set ServiceAllowList to ["1108","110A","110B","110C","110D","110E", "110F","1112","111E","111F","1203"]
( users are only allowed to connect headset )
2. Turn on paired WF1000XM3, and listen music on Youtube.
3. Turn on paired K830 (LE device), press any key on keyboard.
4. Turn on paired Samsung Bluetooth Keyboard EE-BT550 (BREDR device), press any key on keyboard.
5. Set ServiceAllowList to
["1124","180A","180F","1812"]
( users are only allowed to connect HID devices )
6. Turn on paired WF1000XM3, and listen music on Youtube.
7. Turn on paired K830 (LE device), press any key on keyboard.
8. Turn on paired Samsung Bluetooth Keyboard EE-BT550 (BREDR device), press any key on keyboard.
9. Set ServiceAllowList to []
( users are only allowed to connect any device. )
10. Turn on paired WF1000XM3, and listen music on Youtube.
11. Turn on paired K830 (LE device), press any key on keyboard.
12. Turn on paired Samsung Bluetooth Keyboard EE-BT550 (BREDR device), press any key on keyboard.
Expected results:
Step 2,7,8,9,10,11 should success, and step 3,4,6 should fail.
(no changes since v1)
plugins/admin.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-)
plugins/admin.c +126 -1
@@ -12,19 +12,29 @@#include <config.h> #endif +#include <dbus/dbus.h> +#include <gdbus/gdbus.h> +#include "lib/bluetooth.h" +#include "lib/uuid.h" #include "src/adapter.h" +#include "src/dbus-common.h" #include "src/error.h" #include "src/log.h" #include "src/plugin.h" #include "src/shared/queue.h" +#define ADMIN_POLICY_SET_INTERFACE "org.bluez.AdminPolicySet1" + +static DBusConnection *dbus_conn; +/* |policy_data| has the same life cycle as btd_adapter */ static struct btd_admin_policy {struct btd_adapter *adapter;uint16_t adapter_id; +struct queue *service_allowlist; } *policy_data =NULL ;static struct btd_admin_policy *admin_policy_new (struct btd_adapter *adapter)
@@ -40,19 +50,120 @@ static struct btd_admin_policy *admin_policy_new(struct btd_adapter *adapter) admin_policy->adapter = adapter; admin_policy->adapter_id =btd_adapter_get_index (adapter); + admin_policy->service_allowlist =NULL ;return admin_policy; } +static void free_service_allowlist (struct queue *q) +{ +queue_destroy (q, g_free); +} +static void admin_policy_free (void *data) {struct btd_admin_policy *admin_policy = data; +free_service_allowlist (admin_policy->service_allowlist);g_free (admin_policy); } +static struct queue *parse_allow_service_list (struct btd_adapter *adapter, +DBusMessage *msg) +{ +DBusMessageIter iter, arr_iter; +struct queue *uuid_list =NULL ; + +dbus_message_iter_init (msg, &iter); +if (dbus_message_iter_get_arg_type (&iter) !=DBUS_TYPE_ARRAY ) +return NULL ; + + uuid_list =queue_new (); +dbus_message_iter_recurse (&iter, &arr_iter); +do { +const int type =dbus_message_iter_get_arg_type (&arr_iter); +char *uuid_param; +bt_uuid_t *uuid; + +if (type ==DBUS_TYPE_INVALID ) +break ; + +if (type !=DBUS_TYPE_STRING ) + goto failed; + +dbus_message_iter_get_basic (&arr_iter, &uuid_param); + + uuid =g_try_malloc (sizeof (*uuid)); +if (!uuid) + goto failed; + +if (bt_string_to_uuid (uuid, uuid_param)) { +g_free (uuid); + goto failed; + } + +queue_push_head (uuid_list, uuid); + +dbus_message_iter_next (&arr_iter); + }while (true); + +return uuid_list; + +failed: +queue_destroy (uuid_list, g_free); +return NULL ; +} + +static bool service_allowlist_set (struct btd_admin_policy *admin_policy, +struct queue *uuid_list) +{ +struct btd_adapter *adapter = admin_policy->adapter; + +if (!btd_adapter_set_allowed_uuids (adapter, uuid_list)) +return false; + +free_service_allowlist (admin_policy->service_allowlist); + admin_policy->service_allowlist = uuid_list; + +return true; +} + +static DBusMessage *set_service_allowlist (DBusConnection *conn, +DBusMessage *msg,void *user_data) +{ +struct btd_admin_policy *admin_policy = user_data; +struct btd_adapter *adapter = admin_policy->adapter; +struct queue *uuid_list =NULL ; +const char *sender =dbus_message_get_sender (msg); + +DBG ("sender %s" , sender); + +/* Parse parameters */ + uuid_list =parse_allow_service_list (adapter, msg); +if (!uuid_list) { +btd_error (admin_policy->adapter_id, +"Failed on parsing allowed service list" ); +return btd_error_invalid_args (msg); + } + +if (!service_allowlist_set (admin_policy, uuid_list)) { +free_service_allowlist (uuid_list); +return btd_error_failed (msg,"service_allowlist_set failed" ); + } + +return dbus_message_new_method_return (msg); +} + +static const GDBusMethodTable admin_policy_adapter_methods[] = { + { GDBUS_METHOD("SetServiceAllowList", GDBUS_ARGS({ "UUIDs", "as" }), +NULL , set_service_allowlist) }, + { } +}; +static int admin_policy_adapter_probe (struct btd_adapter *adapter) { +const char *adapter_path; +if (policy_data) {btd_warn (policy_data->adapter_id,"Policy data already exists" );
@@ -64,8 +175,20 @@ static int admin_policy_adapter_probe(struct btd_adapter *adapter)if (!policy_data)return -ENOMEM ; -btd_info (policy_data->adapter_id,"Admin Policy has been enabled" ); + adapter_path =adapter_get_path (adapter); +if (!g_dbus_register_interface (dbus_conn, adapter_path, +ADMIN_POLICY_SET_INTERFACE , + admin_policy_adapter_methods,NULL , +NULL , policy_data, admin_policy_free)) { +btd_error (policy_data->adapter_id, +"Admin Policy Set interface init failed on path %s" , + adapter_path); +return -EINVAL ; + } + +btd_info (policy_data->adapter_id, +"Admin Policy Set interface registered" );return 0 ; }
@@ -79,6 +202,8 @@ static int admin_init(void) {DBG ("" ); + dbus_conn =btd_get_dbus_connection (); +return btd_register_adapter_driver (&admin_policy_driver); }
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 9/13 plugins/admin: add ServiceAllowList property
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This adds code to register interface org.bluez.AdminPolicyStatus. The interface will provide read-only properties to indicate the current settings of admin policies. We separate this from AdminPolicySet so that normal clients can check current policy settings while only a few clients can change policies.
This patch also adds readonly property ServiceAllowlist to AdminPolicyStatus1, which indicates the current setting of service allowlist.
---
The following test steps were performed:
1. Set ServiceAllowList to ["1124","180A","180F","1812"]
2. Verify ServiceAllowList is ["1124","180A","180F","1812"] in UUID-128 form
3. Set ServiceAllowList to []
4. Verify ServiceAllowList is []
(no changes since v1)
plugins/admin.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)
plugins/admin.c +58 -0
@@ -27,6 +27,7 @@#include "src/shared/queue.h" #define ADMIN_POLICY_SET_INTERFACE "org.bluez.AdminPolicySet1" +#define ADMIN_POLICY_STATUS_INTERFACE "org.bluez.AdminPolicyStatus1"static DBusConnection *dbus_conn;
@@ -151,6 +152,11 @@ static DBusMessage *set_service_allowlist(DBusConnection *conn,return btd_error_failed (msg,"service_allowlist_set failed" ); } +g_dbus_emit_property_changed (dbus_conn, +adapter_get_path (policy_data->adapter), +ADMIN_POLICY_STATUS_INTERFACE , +"ServiceAllowList" ); +return dbus_message_new_method_return (msg); }
@@ -160,6 +166,43 @@ static const GDBusMethodTable admin_policy_adapter_methods[] = { { } }; +void append_service_uuid (void *data,void *user_data) +{ +bt_uuid_t *uuid = data; +DBusMessageIter *entry = user_data; +char uuid_str[MAX_LEN_UUID_STR ]; +const char *uuid_str_ptr = uuid_str; + +if (!uuid) { +error ("Unexpected NULL uuid data in service_allowlist" ); +return ; + } + +bt_uuid_to_string (uuid, uuid_str,MAX_LEN_UUID_STR ); +dbus_message_iter_append_basic (entry,DBUS_TYPE_STRING , &uuid_str_ptr); +} + +static gboolean property_get_service_allowlist ( +const GDBusPropertyTable *property, +DBusMessageIter *iter,void *user_data) +{ +struct btd_admin_policy *admin_policy = user_data; +DBusMessageIter entry; + +dbus_message_iter_open_container (iter,DBUS_TYPE_ARRAY , +DBUS_TYPE_STRING_AS_STRING , &entry); +queue_foreach (admin_policy->service_allowlist, append_service_uuid, + &entry); +dbus_message_iter_close_container (iter, &entry); + +return TRUE; +} + +static const GDBusPropertyTable admin_policy_adapter_properties[] = { + {"ServiceAllowList" ,"as" , property_get_service_allowlist }, + { } +}; +static int admin_policy_adapter_probe (struct btd_adapter *adapter) {const char *adapter_path;
@@ -189,6 +232,21 @@ static int admin_policy_adapter_probe(struct btd_adapter *adapter)btd_info (policy_data->adapter_id,"Admin Policy Set interface registered" ); + +if (!g_dbus_register_interface (dbus_conn, adapter_path, +ADMIN_POLICY_STATUS_INTERFACE , +NULL ,NULL , + admin_policy_adapter_properties, + policy_data, admin_policy_free)) { +btd_error (policy_data->adapter_id, +"Admin Policy Status interface init failed on path %s" , + adapter_path); +return -EINVAL ; + } + +btd_info (policy_data->adapter_id, +"Admin Policy Status interface registered" ); +return 0 ; }
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 10/13 plugins/admin: add device callbacks
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This adds callbacks for device added and device removed. It is necessary for implementation of "AffectedByPolicy" property since it needs to register an interface for each device object and unregister it once the device gets removed.
---
The following test steps were performed:
1. start discovery using UI
2. verify device_data were added by checking system log
3. stop discovery
4. verify device_data were removed after a few seconds by checking system log
(no changes since v1)
plugins/admin.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+)
plugins/admin.c +78 -0
@@ -20,6 +20,7 @@#include "src/adapter.h" #include "src/dbus-common.h" +#include "src/device.h" #include "src/error.h" #include "src/log.h" #include "src/plugin.h"
@@ -29,7 +30,11 @@#define ADMIN_POLICY_SET_INTERFACE "org.bluez.AdminPolicySet1"#define ADMIN_POLICY_STATUS_INTERFACE "org.bluez.AdminPolicyStatus1" +#define DBUS_BLUEZ_SERVICE "org.bluez" +#define BTD_DEVICE_INTERFACE "org.bluez.Device1" +static DBusConnection *dbus_conn; +static struct queue *devices;/* List of struct device_data objects */ /* |policy_data| has the same life cycle as btd_adapter */ static struct btd_admin_policy {
@@ -38,6 +43,11 @@ static struct btd_admin_policy {struct queue *service_allowlist; } *policy_data =NULL ; +struct device_data { +struct btd_device *device; +char *path; +}; +static struct btd_admin_policy *admin_policy_new (struct btd_adapter *adapter) {struct btd_admin_policy *admin_policy =NULL ;
@@ -203,6 +213,37 @@ static const GDBusPropertyTable admin_policy_adapter_properties[] = { { } }; +static bool device_data_match (const void *a,const void *b) +{ +const struct device_data *data = a; +const struct btd_device *dev = b; + +if (!data) { +error ("Unexpected NULL device_data" ); +return false; + } + +return data->device == dev; +} + +static void free_device_data (void *data) +{ +struct device_data *device_data = data; + +g_free (device_data->path); +g_free (device_data); +} + +static void remove_device_data (void *data) +{ +struct device_data *device_data = data; + +DBG ("device_data for %s removing" , device_data->path); + +queue_remove (devices, device_data); +free_device_data (device_data); +} +static int admin_policy_adapter_probe (struct btd_adapter *adapter) {const char *adapter_path;
@@ -250,10 +291,45 @@ static int admin_policy_adapter_probe(struct btd_adapter *adapter)return 0 ; } +static void admin_policy_device_added (struct btd_adapter *adapter, +struct btd_device *device) +{ +struct device_data *data; + +if (queue_find (devices, device_data_match, device)) +return ; + + data = g_new0(struct device_data, 1); +if (!data) { +btd_error (btd_adapter_get_index (adapter), +"Failed to allocate memory for device_data" ); +return ; + } + + data->device = device; + data->path =g_strdup (device_get_path (device)); +queue_push_tail (devices, data); + +DBG ("device_data for %s added" , data->path); +} + +static void admin_policy_device_removed (struct btd_adapter *adapter, +struct btd_device *device) +{ +struct device_data *data; + + data =queue_find (devices, device_data_match, device); + +if (data) +remove_device_data (data); +} +static struct btd_adapter_driver admin_policy_driver = { .name ="admin_policy" , .probe = admin_policy_adapter_probe, .resume =NULL , + .device_added = admin_policy_device_added, + .device_removed = admin_policy_device_removed };static int admin_init (void )
@@ -261,6 +337,7 @@ static int admin_init(void)DBG ("" ); dbus_conn =btd_get_dbus_connection (); + devices =queue_new ();return btd_register_adapter_driver (&admin_policy_driver); }
@@ -270,6 +347,7 @@ static void admin_exit(void)DBG ("" );btd_unregister_adapter_driver (&admin_policy_driver); +queue_destroy (devices, free_device_data);if (policy_data)admin_policy_free (policy_data);
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 11/13 plugins/admin: add AffectedByPolicy property
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This adds property to indicate if a device has any service that is being blocked by admin policy.
---
The following test steps were performed:
1. Set ServiceAllowList to []
2. Verify AffectedByPolicy of K830 is False
3. Set ServiceAllowList to
["1800"]
4. Verify AffectedByPolicy of K830 is False
5. Set ServiceAllowList to ["1800","1801","180A","180F","1812"]
6. Verify AffectedByPolicy of K830 is True
(no changes since v1)
plugins/admin.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-)
plugins/admin.c +71 -2
@@ -46,6 +46,7 @@ static struct btd_admin_policy {struct device_data {struct btd_device *device;char *path; +bool affected; };static struct btd_admin_policy *admin_policy_new (struct btd_adapter *adapter)
@@ -139,6 +140,27 @@ static bool service_allowlist_set(struct btd_admin_policy *admin_policy,return true; } +static void update_device_affected (void *data,void *user_data) +{ +struct device_data *dev_data = data; +bool affected; + +if (!dev_data) { +error ("Unexpected NULL device_data when updating device" ); +return ; + } + + affected = !btd_device_all_services_allowed (dev_data->device); + +if (affected == dev_data->affected) +return ; + + dev_data->affected = affected; + +g_dbus_emit_property_changed (dbus_conn, dev_data->path, +ADMIN_POLICY_STATUS_INTERFACE ,"AffectedByPolicy" ); +} +static DBusMessage *set_service_allowlist (DBusConnection *conn,DBusMessage *msg,void *user_data) {
@@ -167,6 +189,8 @@ static DBusMessage *set_service_allowlist(DBusConnection *conn,ADMIN_POLICY_STATUS_INTERFACE , "ServiceAllowList"); +queue_foreach (devices, update_device_affected,NULL ); +return dbus_message_new_method_return (msg); }
@@ -226,6 +250,28 @@ static bool device_data_match(const void *a, const void *b)return data->device == dev; } +static gboolean property_get_affected_by_policy ( +const GDBusPropertyTable *property, +DBusMessageIter *iter,void *user_data) +{ +struct device_data *data = user_data; + +if (!data) { +error ("Unexpected error: device_data is NULL" ); +return FALSE; + } + +dbus_message_iter_append_basic (iter,DBUS_TYPE_BOOLEAN , + &data->affected); + +return TRUE; +} + +static const GDBusPropertyTable admin_policy_device_properties[] = { + {"AffectedByPolicy" ,"b" , property_get_affected_by_policy }, + { } +}; +static void free_device_data (void *data) {struct device_data *device_data = data;
@@ -308,11 +354,33 @@ static void admin_policy_device_added(struct btd_adapter *adapter, data->device = device; data->path =g_strdup (device_get_path (device)); + data->affected = !btd_device_all_services_allowed (data->device); + +if (!g_dbus_register_interface (dbus_conn, data->path, +ADMIN_POLICY_STATUS_INTERFACE , +NULL ,NULL , + admin_policy_device_properties, + data, remove_device_data)) { +btd_error (btd_adapter_get_index (adapter), +"Admin Policy Status interface init failed on path %s" , +device_get_path (device)); +free_device_data (data); +return ; + } +queue_push_tail (devices, data);DBG ("device_data for %s added" , data->path); } +static void unregister_device_data (void *data,void *user_data) +{ +struct device_data *dev_data = data; + +g_dbus_unregister_interface (dbus_conn, dev_data->path, +ADMIN_POLICY_STATUS_INTERFACE ); +} +static void admin_policy_device_removed (struct btd_adapter *adapter,struct btd_device *device) {
@@ -321,7 +389,7 @@ static void admin_policy_device_removed(struct btd_adapter *adapter, data =queue_find (devices, device_data_match, device);if (data) -remove_device_data (data); +unregister_device_data (data,NULL ); }static struct btd_adapter_driver admin_policy_driver = {
@@ -347,7 +415,8 @@ static void admin_exit(void)DBG ("" );btd_unregister_adapter_driver (&admin_policy_driver); -queue_destroy (devices, free_device_data); +queue_foreach (devices, unregister_device_data,NULL ); +queue_destroy (devices, g_free);if (policy_data)admin_policy_free (policy_data);
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
PATCH v7 12/13 plugins/admin: persist policy settings
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This adds code to store the ServiceAllowlist to file /var/lib/bluetooth/{MAC_ADDR}/admin_policy
The stored settings will be loaded upon admin_policy initialized.
---
The following test steps were performed:
1. Set ServiceAllowlist to ["1124","180A","180F","1812", "1801"]
2. restart bluetoothd
3. Verify ServiceAllowlist is ["1124","180A","180F","1812","1801"] in UUID-128 form
4. Set ServiceAllowlist to []
5. restart bluetoothd
6. Verify ServiceAllowlist is []
(no changes since v1)
plugins/admin.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 2 deletions(-)
plugins/admin.c +167 -2
@@ -14,6 +14,9 @@#include <dbus/dbus.h> #include <gdbus/gdbus.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <errno.h> #include "lib/bluetooth.h" #include "lib/uuid.h"
@@ -24,11 +27,13 @@#include "src/error.h" #include "src/log.h" #include "src/plugin.h" +#include "src/textfile.h" #include "src/shared/queue.h" #define ADMIN_POLICY_SET_INTERFACE "org.bluez.AdminPolicySet1"#define ADMIN_POLICY_STATUS_INTERFACE "org.bluez.AdminPolicyStatus1" +#define ADMIN_POLICY_STORAGE STORAGEDIR "/admin_policy_settings"#define DBUS_BLUEZ_SERVICE "org.bluez"#define BTD_DEVICE_INTERFACE "org.bluez.Device1"
@@ -161,6 +166,8 @@ static void update_device_affected(void *data, void *user_data) ADMIN_POLICY_STATUS_INTERFACE, "AffectedByPolicy"); } +static void store_policy_settings (struct btd_admin_policy *admin_policy); +static DBusMessage *set_service_allowlist (DBusConnection *conn,DBusMessage *msg,void *user_data) {
@@ -179,7 +186,9 @@ static DBusMessage *set_service_allowlist(DBusConnection *conn,return btd_error_invalid_args (msg); } -if (!service_allowlist_set (admin_policy, uuid_list)) { +if (service_allowlist_set (admin_policy, uuid_list)) { +store_policy_settings (admin_policy); + }else {free_service_allowlist (uuid_list);return btd_error_failed (msg,"service_allowlist_set failed" ); }
@@ -200,7 +209,7 @@ static const GDBusMethodTable admin_policy_adapter_methods[] = { { } }; -void append_service_uuid (void *data,void *user_data) +static void append_service_uuid (void *data,void *user_data) {bt_uuid_t *uuid = data;DBusMessageIter *entry = user_data;
@@ -237,6 +246,161 @@ static const GDBusPropertyTable admin_policy_adapter_properties[] = { { } }; +static void free_uuid_strings (char **uuid_strs,gsize num) +{ +gsize i; + +for (i =0 ; i < num; i++) +g_free (uuid_strs[i]); +g_free (uuid_strs); +} + +static char **new_uuid_strings (struct queue *allowlist,gsize *num) +{ +const struct queue_entry *entry =NULL ; +bt_uuid_t *uuid =NULL ; +char **uuid_strs =NULL ; +gsize i =0 , allowlist_num; + +/* Set num to a non-zero number so that whoever call this could know if +* this function success or not +*/ + *num =1 ; + + allowlist_num =queue_length (allowlist); + uuid_strs =g_try_malloc_n (allowlist_num,sizeof (char *)); +if (!uuid_strs) +return NULL ; + +for (entry =queue_get_entries (allowlist); entry !=NULL ; + entry = entry->next) { + uuid = entry->data; + uuid_strs[i] =g_try_malloc0 (MAX_LEN_UUID_STR *sizeof (char )); + +if (!uuid_strs[i]) + goto failed; + +bt_uuid_to_string (uuid, uuid_strs[i],MAX_LEN_UUID_STR ); + i++; + } + + *num = allowlist_num; +return uuid_strs; + +failed: +free_uuid_strings (uuid_strs, i); + +return NULL ; +} + +static void store_policy_settings (struct btd_admin_policy *admin_policy) +{ +GKeyFile *key_file =NULL ; +char *filename =ADMIN_POLICY_STORAGE ; +char *key_file_data =NULL ; +char **uuid_strs =NULL ; +gsize length, num_uuids; + + key_file =g_key_file_new (); + + uuid_strs =new_uuid_strings (admin_policy->service_allowlist, + &num_uuids); + +if (!uuid_strs && num_uuids) { +btd_error (admin_policy->adapter_id, +"Failed to allocate uuid strings" ); + goto failed; + } + +g_key_file_set_string_list (key_file,"General" ,"ServiceAllowlist" , + (const gchar *const *)uuid_strs, + num_uuids); + +if (create_file (ADMIN_POLICY_STORAGE ,0600 ) <0 ) { +btd_error (admin_policy->adapter_id,"create %s failed, %s" , + filename,strerror (errno)); + goto failed; + } + + key_file_data =g_key_file_to_data (key_file, &length,NULL ); +g_file_set_contents (ADMIN_POLICY_STORAGE , key_file_data, length,NULL ); + +g_free (key_file_data); +free_uuid_strings (uuid_strs, num_uuids); + +failed: +g_key_file_free (key_file); +} + +static void key_file_load_service_allowlist (GKeyFile *key_file, +struct btd_admin_policy *admin_policy) +{ +GError *gerr =NULL ; +struct queue *uuid_list =NULL ; +gchar **uuids =NULL ; +gsize num, i; + + uuids =g_key_file_get_string_list (key_file,"General" , +"ServiceAllowlist" , &num, &gerr); + +if (gerr) { +btd_error (admin_policy->adapter_id, +"Failed to load ServiceAllowlist" ); +g_error_free (gerr); +return ; + } + + uuid_list =queue_new (); +for (i =0 ; i < num; i++) { +bt_uuid_t *uuid =g_try_malloc (sizeof (*uuid)); + +if (!uuid) + goto failed; + +if (bt_string_to_uuid (uuid, *uuids)) { + +btd_error (admin_policy->adapter_id, +"Failed to convert '%s' to uuid struct" , + *uuids); + +g_free (uuid); + goto failed; + } + +queue_push_tail (uuid_list, uuid); + uuids++; + } + +if (!service_allowlist_set (admin_policy, uuid_list)) + goto failed; + +return ; +failed: +free_service_allowlist (uuid_list); +} + +static void load_policy_settings (struct btd_admin_policy *admin_policy) +{ +GKeyFile *key_file; +char *filename =ADMIN_POLICY_STORAGE ; +struct stat st; + +if (stat (filename, &st) <0 ) { +btd_error (admin_policy->adapter_id, +"Failed to get file %s information" , + filename); +return ; + } + + key_file =g_key_file_new (); + +g_key_file_load_from_file (key_file, filename,0 ,NULL ); + +key_file_load_service_allowlist (key_file, admin_policy); + +g_key_file_free (key_file); +} +static bool device_data_match (const void *a,const void *b) {const struct device_data *data = a;
@@ -305,6 +469,7 @@ static int admin_policy_adapter_probe(struct btd_adapter *adapter)if (!policy_data)return -ENOMEM ; +load_policy_settings (policy_data); adapter_path =adapter_get_path (adapter); if (!g_dbus_register_interface(dbus_conn, adapter_path,
Signature · 1 line
2.32.0.554.ge1b32706d8-goog
Luiz Augusto von Dentz
maintainerRe: [Bluez PATCH v7 12/13] plugins/admin: persist policy settings
Hi Howard,
Quoted 8 lines · Howard Chung
From: Yun-Hao Chung <[email protected]>
This adds code to store the ServiceAllowlist to file
/var/lib/bluetooth/{MAC_ADDR}/admin_policy
The stored settings will be loaded uponadmin_policyinitialized.Reviewed-by Miao-chen Chou <[email protected]>
Quoted 9 lines
---
The following test steps were performed:
1. Set ServiceAllowlist to ["1124","180A","180F","1812", "1801"]
2. restart bluetoothd
3. Verify ServiceAllowlist is ["1124","180A","180F","1812","1801"] in UUID-128 form
4. Set ServiceAllowlist to []
5. restart bluetoothd
6. Verify ServiceAllowlist is []
Please have the format documented in doc/settings-storage.txt
Quoted 34 lines
(no changes since v1)
plugins/admin.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 2 deletions(-)plugins/admin.c +5
-0@@ -14,6 +14,9 @@#include <dbus/dbus.h> #include <gdbus/gdbus.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <errno.h> #include "lib/bluetooth.h" #include "lib/uuid.h" @@ -24,11 +27,13 @@#include "src/error.h" #include "src/log.h" #include "src/plugin.h" +#include "src/textfile.h" #include "src/shared/queue.h" #define ADMIN_POLICY_SET_INTERFACE "org.bluez.AdminPolicySet1"#define ADMIN_POLICY_STATUS_INTERFACE "org.bluez.AdminPolicyStatus1" +#define ADMIN_POLICY_STORAGE STORAGEDIR "/admin_policy_settings"#define DBUS_BLUEZ_SERVICE "org.bluez"#define BTD_DEVICE_INTERFACE "org.bluez.Device1"
plugins/admin.c static void update_device_affected(void *data, void *user_data) · line 169
Quoted 4 lines
plugins/admin.c +1
-0@@ -161,6 +166,8 @@ static void update_device_affected(void *data, void *user_data) ADMIN_POLICY_STATUS_INTERFACE, "AffectedByPolicy"); } +static void store_policy_settings (struct btd_admin_policy *admin_policy);
Usually we recommend avoiding forward declaration if possible.
Quoted 196 lines
plugins/admin.c +160
-3static DBusMessage *set_service_allowlist (DBusConnection *conn,DBusMessage *msg,void *user_data) {@@ -179,7 +186,9 @@ static DBusMessage *set_service_allowlist(DBusConnection *conn,return btd_error_invalid_args (msg); } -if (!service_allowlist_set (admin_policy, uuid_list)) { +if (service_allowlist_set (admin_policy, uuid_list)) { +store_policy_settings (admin_policy); + }else {free_service_allowlist (uuid_list);return btd_error_failed (msg,"service_allowlist_set failed" ); }@@ -200,7 +209,7 @@ static const GDBusMethodTable admin_policy_adapter_methods[] = { { } }; -void append_service_uuid (void *data,void *user_data) +static void append_service_uuid (void *data,void *user_data) {bt_uuid_t *uuid = data;DBusMessageIter *entry = user_data;@@ -237,6 +246,161 @@ static const GDBusPropertyTable admin_policy_adapter_properties[] = { { } }; +static void free_uuid_strings (char **uuid_strs,gsize num) +{ +gsize i; + +for (i =0 ; i < num; i++) +g_free (uuid_strs[i]); +g_free (uuid_strs); +} + +static char **new_uuid_strings (struct queue *allowlist,gsize *num) +{ +const struct queue_entry *entry =NULL ; +bt_uuid_t *uuid =NULL ; +char **uuid_strs =NULL ; +gsize i =0 , allowlist_num; + +/* Set num to a non-zero number so that whoever call this could know if +* this function success or not +*/ + *num =1 ; + + allowlist_num =queue_length (allowlist); + uuid_strs =g_try_malloc_n (allowlist_num,sizeof (char *)); +if (!uuid_strs) +return NULL ; + +for (entry =queue_get_entries (allowlist); entry !=NULL ; + entry = entry->next) { + uuid = entry->data; + uuid_strs[i] =g_try_malloc0 (MAX_LEN_UUID_STR *sizeof (char )); + +if (!uuid_strs[i]) + goto failed; + +bt_uuid_to_string (uuid, uuid_strs[i],MAX_LEN_UUID_STR ); + i++; + } + + *num = allowlist_num; +return uuid_strs; + +failed: +free_uuid_strings (uuid_strs, i); + +return NULL ; +} + +static void store_policy_settings (struct btd_admin_policy *admin_policy) +{ +GKeyFile *key_file =NULL ; +char *filename =ADMIN_POLICY_STORAGE ; +char *key_file_data =NULL ; +char **uuid_strs =NULL ; +gsize length, num_uuids; + + key_file =g_key_file_new (); + + uuid_strs =new_uuid_strings (admin_policy->service_allowlist, + &num_uuids); + +if (!uuid_strs && num_uuids) { +btd_error (admin_policy->adapter_id, +"Failed to allocate uuid strings" ); + goto failed; + } + +g_key_file_set_string_list (key_file,"General" ,"ServiceAllowlist" , + (const gchar *const *)uuid_strs, + num_uuids); + +if (create_file (ADMIN_POLICY_STORAGE ,0600 ) <0 ) { +btd_error (admin_policy->adapter_id,"create %s failed, %s" , + filename,strerror (errno)); + goto failed; + } + + key_file_data =g_key_file_to_data (key_file, &length,NULL ); +g_file_set_contents (ADMIN_POLICY_STORAGE , key_file_data, length,NULL ); + +g_free (key_file_data); +free_uuid_strings (uuid_strs, num_uuids); + +failed: +g_key_file_free (key_file); +} + +static void key_file_load_service_allowlist (GKeyFile *key_file, +struct btd_admin_policy *admin_policy) +{ +GError *gerr =NULL ; +struct queue *uuid_list =NULL ; +gchar **uuids =NULL ; +gsize num, i; + + uuids =g_key_file_get_string_list (key_file,"General" , +"ServiceAllowlist" , &num, &gerr); + +if (gerr) { +btd_error (admin_policy->adapter_id, +"Failed to load ServiceAllowlist" ); +g_error_free (gerr); +return ; + } + + uuid_list =queue_new (); +for (i =0 ; i < num; i++) { +bt_uuid_t *uuid =g_try_malloc (sizeof (*uuid)); + +if (!uuid) + goto failed; + +if (bt_string_to_uuid (uuid, *uuids)) { + +btd_error (admin_policy->adapter_id, +"Failed to convert '%s' to uuid struct" , + *uuids); + +g_free (uuid); + goto failed; + } + +queue_push_tail (uuid_list, uuid); + uuids++; + } + +if (!service_allowlist_set (admin_policy, uuid_list)) + goto failed; + +return ; +failed: +free_service_allowlist (uuid_list); +} + +static void load_policy_settings (struct btd_admin_policy *admin_policy) +{ +GKeyFile *key_file; +char *filename =ADMIN_POLICY_STORAGE ; +struct stat st; + +if (stat (filename, &st) <0 ) { +btd_error (admin_policy->adapter_id, +"Failed to get file %s information" , + filename); +return ; + } + + key_file =g_key_file_new (); + +g_key_file_load_from_file (key_file, filename,0 ,NULL ); + +key_file_load_service_allowlist (key_file, admin_policy); + +g_key_file_free (key_file); +} +static bool device_data_match (const void *a,const void *b) {const struct device_data *data = a;@@ -305,6 +469,7 @@ static int admin_policy_adapter_probe(struct btd_adapter *adapter)if (!policy_data)return -ENOMEM ; +load_policy_settings (policy_data); adapter_path =adapter_get_path (adapter); if (!g_dbus_register_interface(dbus_conn, adapter_path, --2.32.0.554.ge1b32706d8-goog
Signature · 1 line
Luiz Augusto von Dentz
PATCH v7 13/13 doc: add description of admin policy
In reply to Howard ChungFrom: Yun-Hao Chung <[email protected]>
This adds admin-policy-api.txt.
---
(no changes since v1)
doc/admin-policy-api.txt | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 doc/admin-policy-api.txt
doc/admin-policy-api.txt new file +65 -0
@@ -0,0 +1,65 @@ +BlueZ D-Bus Admin Policy API description +*********************************** + +This API provides methods to control the behavior of bluez as an administrator. + +Interface AdminPolicySet1 provides methods to set policies. Once the policy is +set successfully, it will affect all clients and stay persistently even after +restarting Bluetooth Daemon. The only way to clear it is to overwrite the +policy with the same method. + +Interface AdminPolicyStatus1 provides readonly properties to indicate the +current values of admin policy. + + +Admin Policy Set hierarchy +================= + +Service org.bluez +Interface org.bluez.AdminPolicySet1 +Object path [variable prefix]/{hci0,hci1,...} + +Methods void SetServiceAllowList(array{string} UUIDs) + + This method sets the service allowlist by specifying + service UUIDs. + + When SetServiceAllowList is called, bluez will block + incoming and outgoing connections to the service not in + UUIDs for all of the clients. + + Any subsequent calls to this method will supersede any + previously set allowlist values. Calling this method + with an empty array will allow any service UUIDs to be + used. + + The default value is an empty array. + + Possible errors: org.bluez.Error.InvalidArguments + org.bluez.Error.Failed + + +Admin Policy Status hierarchy +================= + +Service org.bluez +Interface org.bluez.AdminPolicyStatus1 +Object path [variable prefix]/{hci0,hci1,...} + +Properties array{string} ServiceAllowList [readonly] + + Current value of service allow list. + + + +Admin Policy Status hierarchy +================= + +Service org.bluez +Interface org.bluez.AdminPolicyStatus1 +Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX + +Properties bool IsAffectedByPolicy [readonly] + + Indicate if there is any auto-connect profile in this + device is not allowed by admin policy.
Signature · 1 line
2.32.0.554.ge1b32706d8-goog