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.
This commit is contained in:
Alexander Larsson committed 2017-09-01 15:33:31 +02:00
1 parent a8e2dcc1c3
commit ec902a08fa
3 files changed
+134 -6

No files matched your search

+19 -3
View File
@@ -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))
+111 -3
View File
@@ -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);
}
+4
View File
@@ -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);