From ec902a08fa0224a3f862e48a0617c6e7d8208182 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 1 Sep 2017 15:31:34 +0200 Subject: [PATCH] dbus-proxy: Add support for filtering on iface/member/path This adds a new policy level FILTERED which is betweew SEEN and TALK. It implies all that SEEN does, but additionally lets you send method calls to a well known name that matches a filter which can match against interface name, member name and object path. Note: To make the implementation simpler, this does not grant similar access when sending the peer messages via the unique name, only when using the well known name does this work. --- dbus-proxy/dbus-proxy.c | 22 ++++++- dbus-proxy/flatpak-proxy.c | 114 ++++++++++++++++++++++++++++++++++++- dbus-proxy/flatpak-proxy.h | 4 ++ 3 files changed, 134 insertions(+), 6 deletions(-) diff --git a/dbus-proxy/dbus-proxy.c b/dbus-proxy/dbus-proxy.c index 18ccfb225..bd97f9366 100644 --- a/dbus-proxy/dbus-proxy.c +++ b/dbus-proxy/dbus-proxy.c @@ -91,6 +91,7 @@ start_proxy (int n_args, const char *args[]) if (g_str_has_prefix (args[n], "--see=") || g_str_has_prefix (args[n], "--talk=") || + g_str_has_prefix (args[n], "--filter=") || g_str_has_prefix (args[n], "--own=")) { FlatpakPolicy policy = FLATPAK_POLICY_SEE; @@ -99,14 +100,29 @@ start_proxy (int n_args, const char *args[]) if (args[n][2] == 't') policy = FLATPAK_POLICY_TALK; + else if (args[n][2] == 'f') + policy = FLATPAK_POLICY_FILTERED; else if (args[n][2] == 'o') policy = FLATPAK_POLICY_OWN; name = g_strdup (strchr (args[n], '=') + 1); - if (g_str_has_suffix (name, ".*")) + + if (policy == FLATPAK_POLICY_FILTERED) { - name[strlen (name) - 2] = 0; - wildcard = TRUE; + char *rule = strchr (name, '='); + if (rule != NULL) + { + *rule++ = 0; + flatpak_proxy_add_filter (proxy, name, rule); + } + } + else + { + if (g_str_has_suffix (name, ".*")) + { + name[strlen (name) - 2] = 0; + wildcard = TRUE; + } } if (name[0] == ':' || !g_dbus_is_name (name)) diff --git a/dbus-proxy/flatpak-proxy.c b/dbus-proxy/flatpak-proxy.c index 5e1578bf7..b99beebfe 100644 --- a/dbus-proxy/flatpak-proxy.c +++ b/dbus-proxy/flatpak-proxy.c @@ -73,8 +73,11 @@ * You can call the GetXXX methods on the name/id to get e.g. the peer pid * You get AccessDenied rather than NameHasNoOwner when sending messages to the name/id * + * FILTERED: + * You can send *some* method calls to the name (not id) + * * TALK: - * You can send method calls and signals to the name/id + * You can send any method calls and signals to the name/id * You will receive broadcast signals from the name/id (if you have a match rule for them) * You can call StartServiceByName on the name * @@ -218,6 +221,13 @@ typedef struct guint32 unix_fds; } Header; +typedef struct +{ + char *path; + char *interface; + char *member; +} Filter; + static void header_free (Header *header); G_DEFINE_AUTOPTR_CLEANUP_FUNC (Header, header_free) @@ -282,6 +292,7 @@ struct FlatpakProxy GHashTable *wildcard_policy; GHashTable *policy; + GHashTable *filters; }; typedef struct @@ -468,7 +479,11 @@ flatpak_proxy_add_policy (FlatpakProxy *proxy, const char *name, FlatpakPolicy policy) { - g_hash_table_replace (proxy->policy, g_strdup (name), GINT_TO_POINTER (policy)); + guint current_policy = GPOINTER_TO_INT (g_hash_table_lookup (proxy->policy, name)); + + current_policy = MAX (policy, current_policy); + + g_hash_table_replace (proxy->policy, g_strdup (name), GINT_TO_POINTER (current_policy)); } void @@ -479,6 +494,77 @@ flatpak_proxy_add_wildcarded_policy (FlatpakProxy *proxy, g_hash_table_replace (proxy->wildcard_policy, g_strdup (name), GINT_TO_POINTER (policy)); } +static void +filter_free (Filter *filter) +{ + g_free (filter->path); + g_free (filter->interface); + g_free (filter->member); + g_free (filter); +} + +static void +filter_list_free (GList *filters) +{ + g_list_free_full (filters, (GDestroyNotify)filter_free); +} + +/* rules are of the form [org.the.interface.[method|*]][@/obj/path] */ +static Filter * +filter_new (const char *rule) +{ + Filter *filter = g_new0 (Filter, 1); + const char *obj_path_start = NULL; + const char *method_end = NULL; + + obj_path_start = strchr (rule, '@'); + if (obj_path_start && obj_path_start[1] != 0) + filter->path = g_strdup (obj_path_start + 1); + + if (obj_path_start != NULL) + method_end = obj_path_start; + else + method_end = rule + strlen(rule); + + if (rule[0] != '@') + { + filter->interface = g_strndup (rule, method_end - rule); + char *dot = strrchr (filter->interface, '.'); + if (dot != NULL) + { + *dot = 0; + if (strcmp (dot+1, "*") != 0) + filter->member = g_strdup (dot + 1); + } + } + + return filter; +} + + +void +flatpak_proxy_add_filter (FlatpakProxy *proxy, + const char *name, + const char *rule) +{ + Filter *filter; + GList *filters, *new_filters; + + filter = filter_new (rule); + if (g_hash_table_lookup_extended (proxy->filters, + name, + NULL, (void **)&filters)) + { + new_filters = g_list_append (filters, filter); + g_assert (new_filters == filters); + } + else + { + filters = g_list_append (NULL, filter); + g_hash_table_insert (proxy->filters, g_strdup (name), filters); + } +} + static void flatpak_proxy_finalize (GObject *object) { @@ -491,6 +577,7 @@ flatpak_proxy_finalize (GObject *object) g_hash_table_destroy (proxy->policy); g_hash_table_destroy (proxy->wildcard_policy); + g_hash_table_destroy (proxy->filters); g_free (proxy->socket_path); g_free (proxy->dbus_address); @@ -1399,9 +1486,29 @@ get_dbus_method_handler (FlatpakProxyClient *client, Header *header) policy = flatpak_proxy_client_get_policy (client, header->destination); if (policy < FLATPAK_POLICY_SEE) return HANDLE_HIDE; - if (policy < FLATPAK_POLICY_TALK) + if (policy < FLATPAK_POLICY_FILTERED) return HANDLE_DENY; + if (policy == FLATPAK_POLICY_FILTERED) + { + GList *filters = NULL, *l; + + if (header->destination) + filters = g_hash_table_lookup (client->proxy->filters, header->destination); + for (l = filters; l != NULL; l = l->next) + { + Filter *filter = l->data; + + if (header->type == G_DBUS_MESSAGE_TYPE_METHOD_CALL && + (filter->path == NULL || g_strcmp0 (filter->path, header->path) == 0) && + (filter->interface == NULL || g_strcmp0 (filter->interface, header->interface) == 0) && + (filter->member == NULL || g_strcmp0 (filter->member, header->member) == 0)) + return HANDLE_PASS; + } + + return HANDLE_DENY; + } + if (!is_for_bus (header)) return HANDLE_PASS; @@ -2419,6 +2526,7 @@ static void flatpak_proxy_init (FlatpakProxy *proxy) { proxy->policy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + proxy->filters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)filter_list_free); proxy->wildcard_policy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); flatpak_proxy_add_policy (proxy, "org.freedesktop.DBus", FLATPAK_POLICY_TALK); } diff --git a/dbus-proxy/flatpak-proxy.h b/dbus-proxy/flatpak-proxy.h index 8a95f9df9..d7001e7b4 100644 --- a/dbus-proxy/flatpak-proxy.h +++ b/dbus-proxy/flatpak-proxy.h @@ -27,6 +27,7 @@ typedef enum { FLATPAK_POLICY_NONE, FLATPAK_POLICY_SEE, + FLATPAK_POLICY_FILTERED, FLATPAK_POLICY_TALK, FLATPAK_POLICY_OWN } FlatpakPolicy; @@ -53,6 +54,9 @@ void flatpak_proxy_add_policy (FlatpakProxy *proxy, void flatpak_proxy_add_wildcarded_policy (FlatpakProxy *proxy, const char *name, FlatpakPolicy policy); +void flatpak_proxy_add_filter (FlatpakProxy *proxy, + const char *name, + const char *rule); gboolean flatpak_proxy_start (FlatpakProxy *proxy, GError **error); void flatpak_proxy_stop (FlatpakProxy *proxy);