mirror of
https://github.com/flatpak/flatpak.git
synced 2026-03-17 14:39:13 -04:00
dbus-proxy: Rework to match proposed dbus filter behaviour
This reworks the dbus proxy to be more in line with the API proposed at https://bugs.freedesktop.org/show_bug.cgi?id=101902 In particular, it makes the filtering language more expressive. You can now filter both calls and broadcast recieves, and filters now work with wildcarded object paths, bus names and interfaces (BUS_NAME_IS_SUBTREE, OBJECT_PATH_IS_SUBTREE and empty interface in dbus API). We also more correctly track the rules for unique ids so that filter matching work for those too (previously filters only worked if you sent to the well known bus name, not the unique name). In terms of implementation, things have been simplified to *only* use Filter rules rather than tracking policies and filters separately. Also we track all the previously known owned names for a unique id rather than just the highest policy for it. We can then look up all filters for it, instead of a simplified policy only check. In terms of the CLI everything is the same, except --filter=foo has been renamed to --call=foo, to avoid the weird conflict with the --filter (no =..) option. We also added a similar --broadcast to filter received broadcasts. Closes: #1730 Approved by: alexlarsson
This commit is contained in:
committed by
Atomic Bot
parent
d59e79ee79
commit
905e38115c
@@ -616,13 +616,13 @@ flatpak_run_add_a11y_dbus_args (FlatpakBwrap *app_bwrap,
|
||||
flatpak_bwrap_add_args (proxy_arg_bwrap,
|
||||
a11y_address,
|
||||
proxy_socket, "--filter", "--sloppy-names",
|
||||
"--filter=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Embed@/org/a11y/atspi/accessible/root",
|
||||
"--filter=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Unembed@/org/a11y/atspi/accessible/root",
|
||||
"--filter=org.a11y.atspi.Registry=org.a11y.atspi.Registry.GetRegisteredEvents@/org/a11y/atspi/registry",
|
||||
"--filter=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetKeystrokeListeners@/org/a11y/atspi/registry/deviceeventcontroller",
|
||||
"--filter=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetDeviceEventListeners@/org/a11y/atspi/registry/deviceeventcontroller",
|
||||
"--filter=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersSync@/org/a11y/atspi/registry/deviceeventcontroller",
|
||||
"--filter=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersAsync@/org/a11y/atspi/registry/deviceeventcontroller",
|
||||
"--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Embed@/org/a11y/atspi/accessible/root",
|
||||
"--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Unembed@/org/a11y/atspi/accessible/root",
|
||||
"--call=org.a11y.atspi.Registry=org.a11y.atspi.Registry.GetRegisteredEvents@/org/a11y/atspi/registry",
|
||||
"--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetKeystrokeListeners@/org/a11y/atspi/registry/deviceeventcontroller",
|
||||
"--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetDeviceEventListeners@/org/a11y/atspi/registry/deviceeventcontroller",
|
||||
"--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersSync@/org/a11y/atspi/registry/deviceeventcontroller",
|
||||
"--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersAsync@/org/a11y/atspi/registry/deviceeventcontroller",
|
||||
NULL);
|
||||
|
||||
if ((flags & FLATPAK_RUN_FLAG_LOG_A11Y_BUS) != 0)
|
||||
|
||||
@@ -160,38 +160,21 @@ start_proxy (GPtrArray *args, int *args_i)
|
||||
|
||||
if (g_str_has_prefix (arg, "--see=") ||
|
||||
g_str_has_prefix (arg, "--talk=") ||
|
||||
g_str_has_prefix (arg, "--filter=") ||
|
||||
g_str_has_prefix (arg, "--own="))
|
||||
{
|
||||
FlatpakPolicy policy = FLATPAK_POLICY_SEE;
|
||||
g_autofree char *name = NULL;
|
||||
g_autofree char *name = g_strdup (strchr (arg, '=') + 1);
|
||||
gboolean wildcard = FALSE;
|
||||
|
||||
if (arg[2] == 't')
|
||||
policy = FLATPAK_POLICY_TALK;
|
||||
else if (arg[2] == 'f')
|
||||
policy = FLATPAK_POLICY_FILTERED;
|
||||
else if (arg[2] == 'o')
|
||||
policy = FLATPAK_POLICY_OWN;
|
||||
|
||||
name = g_strdup (strchr (arg, '=') + 1);
|
||||
|
||||
if (policy == FLATPAK_POLICY_FILTERED)
|
||||
if (g_str_has_suffix (name, ".*"))
|
||||
{
|
||||
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;
|
||||
}
|
||||
name[strlen (name) - 2] = 0;
|
||||
wildcard = TRUE;
|
||||
}
|
||||
|
||||
if (name[0] == ':' || !g_dbus_is_name (name))
|
||||
@@ -200,10 +183,38 @@ start_proxy (GPtrArray *args, int *args_i)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (wildcard)
|
||||
flatpak_proxy_add_wildcarded_policy (proxy, name, policy);
|
||||
flatpak_proxy_add_policy (proxy, name, wildcard, policy);
|
||||
|
||||
*args_i += 1;
|
||||
}
|
||||
else if (g_str_has_prefix (arg, "--call=") ||
|
||||
g_str_has_prefix (arg, "--broadcast="))
|
||||
{
|
||||
g_autofree char *rest = g_strdup (strchr (arg, '=') + 1);
|
||||
char *name = rest;
|
||||
char *rule;
|
||||
char *name_end = strchr (rest, '=');
|
||||
gboolean wildcard = FALSE;
|
||||
|
||||
if (name_end == NULL)
|
||||
{
|
||||
g_printerr ("'%s' is not a valid name + rule\n", rest);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*name_end = 0;
|
||||
rule = name_end + 1;
|
||||
|
||||
if (g_str_has_suffix (name, ".*"))
|
||||
{
|
||||
name[strlen (name) - 2] = 0;
|
||||
wildcard = TRUE;
|
||||
}
|
||||
|
||||
if (g_str_has_prefix (arg, "--call="))
|
||||
flatpak_proxy_add_call_rule (proxy, name, wildcard, rule);
|
||||
else
|
||||
flatpak_proxy_add_policy (proxy, name, policy);
|
||||
flatpak_proxy_add_broadcast_rule (proxy, name, wildcard, rule);
|
||||
|
||||
*args_i += 1;
|
||||
}
|
||||
|
||||
@@ -73,9 +73,6 @@
|
||||
* 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 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)
|
||||
@@ -84,14 +81,22 @@
|
||||
* OWN:
|
||||
* You are allowed to call RequestName/ReleaseName/ListQueuedOwners on the name.
|
||||
*
|
||||
* The policy applies only to signals and method calls. All replies
|
||||
* (errors or method returns) are allowed once for an outstanding
|
||||
* method call, and never otherwise.
|
||||
* Additionally, there can be more detailed filters installed that
|
||||
* limits what messages you can send to and receive broadcasts from.
|
||||
* However, if you can *ever* call or recieve broadcasts from a name (even if
|
||||
* filtered to some subset of paths/interfaces) its visibility is considered
|
||||
* to be as TALK.
|
||||
*
|
||||
* The policy applies only to outgoing signals and method calls and
|
||||
* incoming broadcast. All replies (errors or method returns) are
|
||||
* allowed once for an outstanding method call, and never
|
||||
* otherwise.
|
||||
*
|
||||
* Every peer on the bus is considered priviledged, and we thus trust
|
||||
* it. So we rely on similar proxies to be running for all untrusted
|
||||
* clients. Any such priviledged peer is allowed to send method call
|
||||
* or unicast signal messages to the proxied client. Once another peer
|
||||
* it and don't apply any filtering (except broadcasts). So we rely on
|
||||
* similar proxies to be running for all untrusted clients. Any such
|
||||
* priviledged peer is allowed to send method call or unicast signal
|
||||
* messages to the proxied client. Once another peer
|
||||
* sends you a message the unique id of that peer is now made visible
|
||||
* (policy SEE) to the proxied client, allowing the client to track
|
||||
* caller lifetimes via NameOwnerChanged signals.
|
||||
@@ -155,6 +160,10 @@
|
||||
* * When we get a reply to the initial Hello request we give
|
||||
* our own assigned unique id policy TALK.
|
||||
*
|
||||
* There is also a mode called "sloppy-names" where you automatically get
|
||||
* SEE access to all the unique names on the bus. This is used only for
|
||||
* the a11y bus.
|
||||
*
|
||||
* All messages sent to the bus itself are fully demarshalled
|
||||
* and handled on a per-method basis:
|
||||
*
|
||||
@@ -222,9 +231,23 @@ typedef struct
|
||||
guint32 unix_fds;
|
||||
} Header;
|
||||
|
||||
typedef enum {
|
||||
FILTER_TYPE_CALL = 1<<0,
|
||||
FILTER_TYPE_BROADCAST = 1<<1,
|
||||
} FilterTypeMask;
|
||||
|
||||
#define FILTER_TYPE_ALL (FILTER_TYPE_CALL|FILTER_TYPE_BROADCAST)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
gboolean name_is_subtree;
|
||||
FlatpakPolicy policy;
|
||||
|
||||
/* More detailed filter */
|
||||
FilterTypeMask types;
|
||||
char *path;
|
||||
gboolean path_is_subtree;
|
||||
char *interface;
|
||||
char *member;
|
||||
} Filter;
|
||||
@@ -272,6 +295,7 @@ struct FlatpakProxyClient
|
||||
GHashTable *get_owner_reply;
|
||||
|
||||
GHashTable *unique_id_policy;
|
||||
GHashTable *unique_id_owned_names;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@@ -292,8 +316,6 @@ struct FlatpakProxy
|
||||
gboolean filter;
|
||||
gboolean sloppy_names;
|
||||
|
||||
GHashTable *wildcard_policy;
|
||||
GHashTable *policy;
|
||||
GHashTable *filters;
|
||||
};
|
||||
|
||||
@@ -327,6 +349,12 @@ G_DEFINE_TYPE (FlatpakProxyClient, flatpak_proxy_client, G_TYPE_OBJECT)
|
||||
static void start_reading (ProxySide *side);
|
||||
static void stop_reading (ProxySide *side);
|
||||
|
||||
static void
|
||||
string_list_free (GList *filters)
|
||||
{
|
||||
g_list_free_full (filters, (GDestroyNotify)g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_unref (Buffer *buffer)
|
||||
{
|
||||
@@ -377,6 +405,7 @@ flatpak_proxy_client_finalize (GObject *object)
|
||||
g_hash_table_destroy (client->rewrite_reply);
|
||||
g_hash_table_destroy (client->get_owner_reply);
|
||||
g_hash_table_destroy (client->unique_id_policy);
|
||||
g_hash_table_destroy (client->unique_id_owned_names);
|
||||
|
||||
free_side (&client->client_side);
|
||||
free_side (&client->bus_side);
|
||||
@@ -413,6 +442,7 @@ flatpak_proxy_client_init (FlatpakProxyClient *client)
|
||||
client->rewrite_reply = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
|
||||
client->get_owner_reply = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
|
||||
client->unique_id_policy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
client->unique_id_owned_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)string_list_free);
|
||||
}
|
||||
|
||||
static FlatpakProxyClient *
|
||||
@@ -431,44 +461,6 @@ flatpak_proxy_client_new (FlatpakProxy *proxy, GSocketConnection *connection)
|
||||
return client;
|
||||
}
|
||||
|
||||
/* This behaves like arg0namespace matching in the dbus specification,
|
||||
i.e. match name exactly against a wildcarded policy, or any suffix
|
||||
of name starting with . */
|
||||
static FlatpakPolicy
|
||||
flatpak_proxy_get_wildcard_policy (FlatpakProxy *proxy,
|
||||
const char *_name)
|
||||
{
|
||||
guint policy, wildcard_policy = 0;
|
||||
char *dot;
|
||||
g_autofree char *name = g_strdup (_name);
|
||||
|
||||
do
|
||||
{
|
||||
policy = GPOINTER_TO_INT (g_hash_table_lookup (proxy->wildcard_policy, name));
|
||||
wildcard_policy = MAX (wildcard_policy, policy);
|
||||
|
||||
dot = strrchr (name, '.');
|
||||
if (dot != NULL)
|
||||
*dot = 0;
|
||||
}
|
||||
while (dot != NULL);
|
||||
|
||||
return wildcard_policy;
|
||||
}
|
||||
|
||||
static FlatpakPolicy
|
||||
flatpak_proxy_get_policy (FlatpakProxy *proxy,
|
||||
const char *name)
|
||||
{
|
||||
guint policy, wildcard_policy;
|
||||
|
||||
policy = GPOINTER_TO_INT (g_hash_table_lookup (proxy->policy, name));
|
||||
|
||||
wildcard_policy = flatpak_proxy_get_wildcard_policy (proxy, name);
|
||||
|
||||
return MAX (policy, wildcard_policy);
|
||||
}
|
||||
|
||||
void
|
||||
flatpak_proxy_set_filter (FlatpakProxy *proxy,
|
||||
gboolean filter)
|
||||
@@ -490,29 +482,10 @@ flatpak_proxy_set_log_messages (FlatpakProxy *proxy,
|
||||
proxy->log_messages = log;
|
||||
}
|
||||
|
||||
void
|
||||
flatpak_proxy_add_policy (FlatpakProxy *proxy,
|
||||
const char *name,
|
||||
FlatpakPolicy 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
|
||||
flatpak_proxy_add_wildcarded_policy (FlatpakProxy *proxy,
|
||||
const char *name,
|
||||
FlatpakPolicy policy)
|
||||
{
|
||||
g_hash_table_replace (proxy->wildcard_policy, g_strdup (name), GINT_TO_POINTER (policy));
|
||||
}
|
||||
|
||||
static void
|
||||
filter_free (Filter *filter)
|
||||
{
|
||||
g_free (filter->name);
|
||||
g_free (filter->path);
|
||||
g_free (filter->interface);
|
||||
g_free (filter->member);
|
||||
@@ -525,50 +498,138 @@ 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_new (const char *name,
|
||||
gboolean name_is_subtree,
|
||||
FlatpakPolicy policy)
|
||||
{
|
||||
Filter *filter = g_new0 (Filter, 1);
|
||||
|
||||
filter->name = g_strdup (name);
|
||||
filter->name_is_subtree = name_is_subtree;
|
||||
filter->policy = policy;
|
||||
filter->types = FILTER_TYPE_ALL;
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
// rules are of the form [*|org.the.interface.[method|*]]|[@/obj/path[/*]]
|
||||
static Filter *
|
||||
filter_new_from_rule (const char *name,
|
||||
gboolean name_is_subtree,
|
||||
FilterTypeMask types,
|
||||
const char *rule)
|
||||
{
|
||||
Filter *filter;
|
||||
const char *obj_path_start = NULL;
|
||||
const char *method_end = NULL;
|
||||
|
||||
filter = filter_new (name, name_is_subtree, FLATPAK_POLICY_TALK);
|
||||
filter->types = types;
|
||||
|
||||
obj_path_start = strchr (rule, '@');
|
||||
if (obj_path_start && obj_path_start[1] != 0)
|
||||
filter->path = g_strdup (obj_path_start + 1);
|
||||
{
|
||||
filter->path = g_strdup (obj_path_start + 1);
|
||||
|
||||
if (g_str_has_suffix (filter->path, "/*"))
|
||||
{
|
||||
filter->path_is_subtree = TRUE;
|
||||
filter->path[strlen (filter->path) - 2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj_path_start != NULL)
|
||||
method_end = obj_path_start;
|
||||
else
|
||||
method_end = rule + strlen(rule);
|
||||
|
||||
if (rule[0] != '@')
|
||||
if (method_end != rule)
|
||||
{
|
||||
filter->interface = g_strndup (rule, method_end - rule);
|
||||
char *dot = strrchr (filter->interface, '.');
|
||||
if (dot != NULL)
|
||||
if (rule[0] == '*')
|
||||
{
|
||||
*dot = 0;
|
||||
if (strcmp (dot+1, "*") != 0)
|
||||
filter->member = g_strdup (dot + 1);
|
||||
}
|
||||
/* Both interface and method wildcarded */
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
static gboolean
|
||||
filter_matches (Filter *filter,
|
||||
FilterTypeMask type,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *member)
|
||||
{
|
||||
if ((filter->types & type) == 0)
|
||||
return FALSE;
|
||||
|
||||
if (filter->path)
|
||||
{
|
||||
if (path == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (filter->path_is_subtree)
|
||||
{
|
||||
gsize filter_path_len = strlen (filter->path);
|
||||
if (strncmp (path, filter->path, filter_path_len) != 0 ||
|
||||
(path[filter_path_len] != 0 && path[filter_path_len] != '/'))
|
||||
return FALSE;
|
||||
}
|
||||
else if (strcmp (filter->path, path) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (filter->interface && g_strcmp0 (filter->interface, interface) != 0)
|
||||
return FALSE;
|
||||
|
||||
if (filter->member && g_strcmp0 (filter->member, member) != 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
any_filter_matches (GList *filters,
|
||||
FilterTypeMask type,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *member)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = filters; l != NULL; l = l->next)
|
||||
{
|
||||
Filter *filter = l->data;
|
||||
if (filter_matches (filter, type, path, interface, member))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
flatpak_proxy_add_filter (FlatpakProxy *proxy,
|
||||
Filter *filter)
|
||||
{
|
||||
Filter *filter;
|
||||
GList *filters, *new_filters;
|
||||
|
||||
filter = filter_new (rule);
|
||||
if (g_hash_table_lookup_extended (proxy->filters,
|
||||
name,
|
||||
filter->name,
|
||||
NULL, (void **)&filters))
|
||||
{
|
||||
new_filters = g_list_append (filters, filter);
|
||||
@@ -577,10 +638,43 @@ flatpak_proxy_add_filter (FlatpakProxy *proxy,
|
||||
else
|
||||
{
|
||||
filters = g_list_append (NULL, filter);
|
||||
g_hash_table_insert (proxy->filters, g_strdup (name), filters);
|
||||
g_hash_table_insert (proxy->filters, g_strdup (filter->name), filters);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
flatpak_proxy_add_policy (FlatpakProxy *proxy,
|
||||
const char *name,
|
||||
gboolean name_is_subtree,
|
||||
FlatpakPolicy policy)
|
||||
{
|
||||
Filter *filter = filter_new (name, name_is_subtree, policy);
|
||||
|
||||
flatpak_proxy_add_filter (proxy, filter);
|
||||
}
|
||||
|
||||
void
|
||||
flatpak_proxy_add_call_rule (FlatpakProxy *proxy,
|
||||
const char *name,
|
||||
gboolean name_is_subtree,
|
||||
const char *rule)
|
||||
{
|
||||
Filter *filter = filter_new_from_rule (name, name_is_subtree, FILTER_TYPE_CALL, rule);
|
||||
|
||||
flatpak_proxy_add_filter (proxy, filter);
|
||||
}
|
||||
|
||||
void
|
||||
flatpak_proxy_add_broadcast_rule (FlatpakProxy *proxy,
|
||||
const char *name,
|
||||
gboolean name_is_subtree,
|
||||
const char *rule)
|
||||
{
|
||||
Filter *filter = filter_new_from_rule (name, name_is_subtree, FILTER_TYPE_BROADCAST, rule);
|
||||
|
||||
flatpak_proxy_add_filter (proxy, filter);
|
||||
}
|
||||
|
||||
static void
|
||||
flatpak_proxy_finalize (GObject *object)
|
||||
{
|
||||
@@ -591,8 +685,6 @@ flatpak_proxy_finalize (GObject *object)
|
||||
|
||||
g_assert (proxy->clients == NULL);
|
||||
|
||||
g_hash_table_destroy (proxy->policy);
|
||||
g_hash_table_destroy (proxy->wildcard_policy);
|
||||
g_hash_table_destroy (proxy->filters);
|
||||
|
||||
g_free (proxy->socket_path);
|
||||
@@ -1309,16 +1401,88 @@ print_incoming_header (Header *header)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Filter *match_all[FLATPAK_POLICY_OWN+1] = { NULL };
|
||||
|
||||
|
||||
static FlatpakPolicy
|
||||
flatpak_proxy_client_get_policy (FlatpakProxyClient *client, const char *source)
|
||||
flatpak_proxy_client_get_max_policy_and_matched (FlatpakProxyClient *client,
|
||||
const char *source,
|
||||
GList **matched_filters)
|
||||
{
|
||||
GList *names, *filters, *l;
|
||||
FlatpakPolicy max_policy = FLATPAK_POLICY_NONE;
|
||||
g_autofree char *name = NULL;
|
||||
gboolean exact_name_match;
|
||||
char *dot;
|
||||
|
||||
if (match_all[FLATPAK_POLICY_SEE] == NULL)
|
||||
{
|
||||
match_all[FLATPAK_POLICY_SEE] = filter_new ("", FALSE, FLATPAK_POLICY_SEE);
|
||||
match_all[FLATPAK_POLICY_TALK] = filter_new ("", FALSE, FLATPAK_POLICY_TALK);
|
||||
match_all[FLATPAK_POLICY_OWN] = filter_new ("", FALSE, FLATPAK_POLICY_OWN);
|
||||
}
|
||||
|
||||
if (source == NULL)
|
||||
return FLATPAK_POLICY_TALK; /* All clients can talk to the bus itself */
|
||||
{
|
||||
if (matched_filters)
|
||||
*matched_filters = g_list_append (*matched_filters, match_all[FLATPAK_POLICY_TALK]);
|
||||
|
||||
return FLATPAK_POLICY_TALK; /* All clients can talk to the bus itself */
|
||||
}
|
||||
|
||||
if (source[0] == ':')
|
||||
return GPOINTER_TO_UINT (g_hash_table_lookup (client->unique_id_policy, source));
|
||||
{
|
||||
/* Default to the unique id policy, i.e. TALK for self, and SEE for trusted peers */
|
||||
max_policy = GPOINTER_TO_UINT (g_hash_table_lookup (client->unique_id_policy, source));
|
||||
if (max_policy > FLATPAK_POLICY_NONE && matched_filters)
|
||||
*matched_filters = g_list_append (*matched_filters, match_all[max_policy]);
|
||||
|
||||
return flatpak_proxy_get_policy (client->proxy, source);
|
||||
/* Treat this as the merged list of filters for all the names the unique id ever owned */
|
||||
names = g_hash_table_lookup (client->unique_id_owned_names, source);
|
||||
for (l = names; l != NULL; l = l->next)
|
||||
{
|
||||
const char *owned_name = l->data;
|
||||
max_policy = MAX (max_policy, flatpak_proxy_client_get_max_policy_and_matched (client, owned_name, matched_filters));
|
||||
}
|
||||
|
||||
|
||||
return max_policy;
|
||||
}
|
||||
|
||||
name = g_strdup (source);
|
||||
exact_name_match = TRUE;
|
||||
do
|
||||
{
|
||||
filters = g_hash_table_lookup (client->proxy->filters, name);
|
||||
|
||||
for (l = filters; l != NULL; l = l->next)
|
||||
{
|
||||
Filter *filter = l->data;
|
||||
|
||||
if (exact_name_match || filter->name_is_subtree)
|
||||
{
|
||||
max_policy = MAX (max_policy, filter->policy);
|
||||
if (matched_filters)
|
||||
*matched_filters = g_list_append (*matched_filters, filter);
|
||||
}
|
||||
}
|
||||
|
||||
exact_name_match = FALSE;
|
||||
dot = strrchr (name, '.');
|
||||
if (dot != NULL)
|
||||
*dot = 0;
|
||||
}
|
||||
while (dot != NULL);
|
||||
|
||||
return max_policy;
|
||||
}
|
||||
|
||||
static FlatpakPolicy
|
||||
flatpak_proxy_client_get_max_policy (FlatpakProxyClient *client,
|
||||
const char *source)
|
||||
{
|
||||
return flatpak_proxy_client_get_max_policy_and_matched (client, source, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1335,14 +1499,23 @@ flatpak_proxy_client_update_unique_id_policy (FlatpakProxyClient *client,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
flatpak_proxy_client_update_unique_id_policy_from_name (FlatpakProxyClient *client,
|
||||
const char *unique_id,
|
||||
const char *as_name)
|
||||
flatpak_proxy_client_add_unique_id_owned_name (FlatpakProxyClient *client,
|
||||
const char *unique_id,
|
||||
const char *owned_name)
|
||||
{
|
||||
flatpak_proxy_client_update_unique_id_policy (client,
|
||||
GList *names;
|
||||
gboolean already_added;
|
||||
|
||||
names = NULL;
|
||||
already_added = g_hash_table_lookup_extended (client->unique_id_owned_names,
|
||||
unique_id,
|
||||
flatpak_proxy_get_policy (client->proxy, as_name));
|
||||
NULL, (void **)&names);
|
||||
names = g_list_append (names, g_strdup (owned_name));
|
||||
|
||||
if (!already_added)
|
||||
g_hash_table_insert (client->unique_id_owned_names, g_strdup (unique_id), names);
|
||||
}
|
||||
|
||||
|
||||
@@ -1487,6 +1660,7 @@ get_dbus_method_handler (FlatpakProxyClient *client, Header *header)
|
||||
{
|
||||
FlatpakPolicy policy;
|
||||
const char *method;
|
||||
g_autoptr(GList) filters = NULL;
|
||||
|
||||
if (header->has_reply_serial)
|
||||
{
|
||||
@@ -1499,34 +1673,25 @@ get_dbus_method_handler (FlatpakProxyClient *client, Header *header)
|
||||
return HANDLE_PASS;
|
||||
}
|
||||
|
||||
policy = flatpak_proxy_client_get_policy (client, header->destination);
|
||||
policy = flatpak_proxy_client_get_max_policy_and_matched (client, header->destination, &filters);
|
||||
if (policy < FLATPAK_POLICY_SEE)
|
||||
return HANDLE_HIDE;
|
||||
if (policy < FLATPAK_POLICY_FILTERED)
|
||||
if (policy < FLATPAK_POLICY_TALK)
|
||||
return HANDLE_DENY;
|
||||
|
||||
if (policy == FLATPAK_POLICY_FILTERED)
|
||||
if (!is_for_bus (header))
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (policy == FLATPAK_POLICY_OWN ||
|
||||
any_filter_matches (filters, FILTER_TYPE_CALL,
|
||||
header->path,
|
||||
header->interface,
|
||||
header->member))
|
||||
return HANDLE_PASS;
|
||||
|
||||
return HANDLE_DENY;
|
||||
}
|
||||
|
||||
if (!is_for_bus (header))
|
||||
return HANDLE_PASS;
|
||||
/* Its a bus call */
|
||||
|
||||
if (is_introspection_call (header))
|
||||
{
|
||||
@@ -1662,7 +1827,7 @@ validate_arg0_name (FlatpakProxyClient *client, Buffer *buffer, FlatpakPolicy re
|
||||
g_variant_is_of_type (arg0, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
name = g_variant_get_string (arg0, NULL);
|
||||
name_policy = flatpak_proxy_client_get_policy (client, name);
|
||||
name_policy = flatpak_proxy_client_get_max_policy (client, name);
|
||||
|
||||
if (has_policy)
|
||||
*has_policy = name_policy;
|
||||
@@ -1698,7 +1863,7 @@ filter_names_list (FlatpakProxyClient *client, Buffer *buffer)
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY);
|
||||
for (i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
if (flatpak_proxy_client_get_policy (client, names[i]) >= FLATPAK_POLICY_SEE)
|
||||
if (flatpak_proxy_client_get_max_policy (client, names[i]) >= FLATPAK_POLICY_SEE)
|
||||
g_variant_builder_add (&builder, "s", names[i]);
|
||||
}
|
||||
g_free (names);
|
||||
@@ -1728,7 +1893,7 @@ should_filter_name_owner_changed (FlatpakProxyClient *client, Buffer *buffer)
|
||||
{
|
||||
GDBusMessage *message = g_dbus_message_new_from_blob (buffer->data, buffer->size, 0, NULL);
|
||||
GVariant *body, *arg0, *arg1, *arg2;
|
||||
const gchar *name, *old, *new;
|
||||
const gchar *name, *new;
|
||||
gboolean filter = TRUE;
|
||||
|
||||
if (message == NULL ||
|
||||
@@ -1742,19 +1907,15 @@ should_filter_name_owner_changed (FlatpakProxyClient *client, Buffer *buffer)
|
||||
return TRUE;
|
||||
|
||||
name = g_variant_get_string (arg0, NULL);
|
||||
old = g_variant_get_string (arg1, NULL);
|
||||
new = g_variant_get_string (arg2, NULL);
|
||||
|
||||
if (flatpak_proxy_client_get_policy (client, name) >= FLATPAK_POLICY_SEE ||
|
||||
if (flatpak_proxy_client_get_max_policy (client, name) >= FLATPAK_POLICY_SEE ||
|
||||
(client->proxy->sloppy_names && name[0] == ':'))
|
||||
{
|
||||
if (name[0] != ':')
|
||||
{
|
||||
if (old[0] != 0)
|
||||
flatpak_proxy_client_update_unique_id_policy_from_name (client, old, name);
|
||||
|
||||
if (new[0] != 0)
|
||||
flatpak_proxy_client_update_unique_id_policy_from_name (client, new, name);
|
||||
flatpak_proxy_client_add_unique_id_owned_name (client, new, name);
|
||||
}
|
||||
|
||||
filter = FALSE;
|
||||
@@ -1850,12 +2011,25 @@ queue_initial_name_ops (FlatpakProxyClient *client)
|
||||
gpointer key, value;
|
||||
gboolean has_wildcards = FALSE;
|
||||
|
||||
g_hash_table_iter_init (&iter, client->proxy->policy);
|
||||
g_hash_table_iter_init (&iter, client->proxy->filters);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
const char *name = key;
|
||||
GList *filters = value;
|
||||
gboolean name_needs_subtree = FALSE;
|
||||
GDBusMessage *message;
|
||||
GVariant *match;
|
||||
GList *l;
|
||||
|
||||
for (l = filters; l != NULL; l = l->next)
|
||||
{
|
||||
Filter *filter = l->data;
|
||||
if (filter->name_is_subtree)
|
||||
{
|
||||
name_needs_subtree = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp (name, "org.freedesktop.DBus") == 0)
|
||||
continue;
|
||||
@@ -1863,45 +2037,32 @@ queue_initial_name_ops (FlatpakProxyClient *client)
|
||||
/* AddMatch the name so we get told about ownership changes.
|
||||
Do it before the GetNameOwner to avoid races */
|
||||
message = g_dbus_message_new_method_call ("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "AddMatch");
|
||||
match = g_variant_new_printf ("type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='%s'", name);
|
||||
if (name_needs_subtree)
|
||||
match = g_variant_new_printf ("type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0namespace='%s'", name);
|
||||
else
|
||||
match = g_variant_new_printf ("type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='%s'", name);
|
||||
g_dbus_message_set_body (message, g_variant_new_tuple (&match, 1));
|
||||
queue_fake_message (client, message, EXPECTED_REPLY_FILTER);
|
||||
|
||||
if (client->proxy->log_messages)
|
||||
g_print ("C%d: -> org.freedesktop.DBus fake AddMatch for %s\n", client->last_serial, name);
|
||||
g_print ("C%d: -> org.freedesktop.DBus fake %sAddMatch for %s\n", client->last_serial, name_needs_subtree ? "wildcarded " : "", name);
|
||||
|
||||
/* Get the current owner of the name (if any) so we can apply policy to it */
|
||||
message = g_dbus_message_new_method_call ("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner");
|
||||
g_dbus_message_set_body (message, g_variant_new ("(s)", name));
|
||||
queue_fake_message (client, message, EXPECTED_REPLY_FAKE_GET_NAME_OWNER);
|
||||
g_hash_table_replace (client->get_owner_reply, GINT_TO_POINTER (client->last_serial), g_strdup (name));
|
||||
if (!name_needs_subtree)
|
||||
{
|
||||
/* Get the current owner of the name (if any) so we can apply policy to it */
|
||||
message = g_dbus_message_new_method_call ("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner");
|
||||
g_dbus_message_set_body (message, g_variant_new ("(s)", name));
|
||||
queue_fake_message (client, message, EXPECTED_REPLY_FAKE_GET_NAME_OWNER);
|
||||
g_hash_table_replace (client->get_owner_reply, GINT_TO_POINTER (client->last_serial), g_strdup (name));
|
||||
|
||||
if (client->proxy->log_messages)
|
||||
g_print ("C%d: -> org.freedesktop.DBus fake GetNameOwner for %s\n", client->last_serial, name);
|
||||
}
|
||||
|
||||
/* Same for wildcard proxies. Only here we don't know the actual names to GetNameOwner for, so we have to
|
||||
list all current names */
|
||||
g_hash_table_iter_init (&iter, client->proxy->wildcard_policy);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
const char *name = key;
|
||||
GDBusMessage *message;
|
||||
GVariant *match;
|
||||
|
||||
has_wildcards = TRUE;
|
||||
|
||||
/* AddMatch the name with arg0namespace so we get told about ownership changes to all subnames.
|
||||
Do it before the GetNameOwner to avoid races */
|
||||
message = g_dbus_message_new_method_call ("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "AddMatch");
|
||||
match = g_variant_new_printf ("type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0namespace='%s'", name);
|
||||
g_dbus_message_set_body (message, g_variant_new_tuple (&match, 1));
|
||||
queue_fake_message (client, message, EXPECTED_REPLY_FILTER);
|
||||
|
||||
if (client->proxy->log_messages)
|
||||
g_print ("C%d: -> org.freedesktop.DBus fake AddMatch for %s.*\n", client->last_serial, name);
|
||||
if (client->proxy->log_messages)
|
||||
g_print ("C%d: -> org.freedesktop.DBus fake GetNameOwner for %s\n", client->last_serial, name);
|
||||
}
|
||||
else
|
||||
has_wildcards = TRUE; /* Send ListNames below */
|
||||
}
|
||||
|
||||
/* For wildcarded rules we don't know the actual names to GetNameOwner for, so we have to list all current names */
|
||||
if (has_wildcards)
|
||||
{
|
||||
GDBusMessage *message;
|
||||
@@ -1918,6 +2079,8 @@ queue_initial_name_ops (FlatpakProxyClient *client)
|
||||
/* Stop reading from the client, to avoid incoming messages fighting with the ListNames roundtrip.
|
||||
We will start it again once we have handled the ListNames reply */
|
||||
stop_reading (&client->client_side);
|
||||
|
||||
/* Once we get the reply to this queue_wildcard_initial_name_ops() will be called and we continue there */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1936,14 +2099,14 @@ queue_wildcard_initial_name_ops (FlatpakProxyClient *client, Header *header, Buf
|
||||
const gchar **names = g_variant_get_strv (arg0, NULL);
|
||||
int i;
|
||||
|
||||
/* Loop over all current names and get the owner for all the ones that match our wildcard
|
||||
/* Loop over all current names and get the owner for all the ones that match our rules
|
||||
policies so that we can update the unique id policies for those */
|
||||
for (i = 0; names[i] != NULL; i++)
|
||||
{
|
||||
const char *name = names[i];
|
||||
|
||||
if (name[0] != ':' &&
|
||||
flatpak_proxy_get_wildcard_policy (client->proxy, name) != FLATPAK_POLICY_NONE)
|
||||
flatpak_proxy_client_get_max_policy (client, name) != FLATPAK_POLICY_NONE)
|
||||
{
|
||||
/* Get the current owner of the name (if any) so we can apply policy to it */
|
||||
GDBusMessage *message = g_dbus_message_new_method_call ("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner");
|
||||
@@ -2227,7 +2390,7 @@ got_buffer_from_bus (FlatpakProxyClient *client, ProxySide *side, Buffer *buffer
|
||||
if (header->type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN)
|
||||
{
|
||||
g_autofree char *owner = get_arg0_string (buffer);
|
||||
flatpak_proxy_client_update_unique_id_policy_from_name (client, owner, requested_name);
|
||||
flatpak_proxy_client_add_unique_id_owned_name (client, owner, requested_name);
|
||||
}
|
||||
|
||||
g_hash_table_remove (client->get_owner_reply, GINT_TO_POINTER (header->reply_serial));
|
||||
@@ -2289,8 +2452,20 @@ got_buffer_from_bus (FlatpakProxyClient *client, ProxySide *side, Buffer *buffer
|
||||
/* All incoming broadcast signals are filtered according to policy */
|
||||
if (header->type == G_DBUS_MESSAGE_TYPE_SIGNAL && header->destination == NULL)
|
||||
{
|
||||
policy = flatpak_proxy_client_get_policy (client, header->sender);
|
||||
if (policy < FLATPAK_POLICY_TALK)
|
||||
g_autoptr(GList) filters = NULL;
|
||||
gboolean filtered = TRUE;
|
||||
|
||||
policy = flatpak_proxy_client_get_max_policy_and_matched (client, header->sender, &filters);
|
||||
|
||||
if (policy == FLATPAK_POLICY_OWN ||
|
||||
(policy == FLATPAK_POLICY_TALK &&
|
||||
any_filter_matches (filters, FILTER_TYPE_BROADCAST,
|
||||
header->path,
|
||||
header->interface,
|
||||
header->member)))
|
||||
filtered = FALSE;
|
||||
|
||||
if (filtered)
|
||||
{
|
||||
if (client->proxy->log_messages)
|
||||
g_print ("*FILTERED IN*\n");
|
||||
@@ -2591,10 +2766,8 @@ flatpak_proxy_incoming (GSocketService *service,
|
||||
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);
|
||||
flatpak_proxy_add_policy (proxy, "org.freedesktop.DBus", FALSE, FLATPAK_POLICY_TALK);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
typedef enum {
|
||||
FLATPAK_POLICY_NONE,
|
||||
FLATPAK_POLICY_SEE,
|
||||
FLATPAK_POLICY_FILTERED,
|
||||
FLATPAK_POLICY_TALK,
|
||||
FLATPAK_POLICY_OWN
|
||||
} FlatpakPolicy;
|
||||
@@ -52,13 +51,16 @@ void flatpak_proxy_set_sloppy_names (FlatpakProxy *proxy,
|
||||
gboolean sloppy_names);
|
||||
void flatpak_proxy_add_policy (FlatpakProxy *proxy,
|
||||
const char *name,
|
||||
gboolean name_is_subtree,
|
||||
FlatpakPolicy policy);
|
||||
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);
|
||||
void flatpak_proxy_add_call_rule (FlatpakProxy *proxy,
|
||||
const char *name,
|
||||
gboolean name_is_subtree,
|
||||
const char *rule);
|
||||
void flatpak_proxy_add_broadcast_rule (FlatpakProxy *proxy,
|
||||
const char *name,
|
||||
gboolean name_is_subtree,
|
||||
const char *rule);
|
||||
gboolean flatpak_proxy_start (FlatpakProxy *proxy,
|
||||
GError **error);
|
||||
void flatpak_proxy_stop (FlatpakProxy *proxy);
|
||||
|
||||
Reference in New Issue
Block a user