Merge branch 'send_destination_prefix' into 'master'

Send destination prefix

See merge request dbus/dbus!85
This commit is contained in:
Simon McVittie 2019-05-30 14:49:09 +00:00
commit 463ecfb4fd
16 changed files with 603 additions and 16 deletions

View file

@ -1298,6 +1298,7 @@ append_rule_from_element (BusConfigParser *parser,
const char *send_member;
const char *send_error;
const char *send_destination;
const char *send_destination_prefix;
const char *send_path;
const char *send_type;
const char *send_requested_reply;
@ -1341,6 +1342,7 @@ append_rule_from_element (BusConfigParser *parser,
"send_member", &send_member,
"send_error", &send_error,
"send_destination", &send_destination,
"send_destination_prefix", &send_destination_prefix,
"send_path", &send_path,
"send_type", &send_type,
"send_broadcast", &send_broadcast,
@ -1364,6 +1366,7 @@ append_rule_from_element (BusConfigParser *parser,
return FALSE;
any_send_attribute = (send_destination != NULL ||
send_destination_prefix != NULL ||
send_broadcast != NULL ||
send_path != NULL ||
send_type != NULL ||
@ -1417,7 +1420,8 @@ append_rule_from_element (BusConfigParser *parser,
* interface + member
* error
*
* base send_ can combine with send_destination, send_path, send_type, send_requested_reply, send_broadcast, eavesdrop
* base send_ can combine with send_destination, send_destination_prefix, send_path, send_type, send_requested_reply, send_broadcast, eavesdrop
* send_destination must not occur with send_destination_prefix
* base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop
*
* user, group, own, own_prefix must occur alone
@ -1456,6 +1460,16 @@ append_rule_from_element (BusConfigParser *parser,
return FALSE;
}
if ((send_destination != NULL) + (send_destination_prefix != NULL) > 1)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Invalid combination of attributes on element <%s>: "
"send_destination cannot be combined with "
"send_destination_prefix",
element_name);
return FALSE;
}
if ((receive_member != NULL || receive_interface != NULL) &&
receive_error != NULL)
{
@ -1589,7 +1603,16 @@ append_rule_from_element (BusConfigParser *parser,
rule->d.send.interface = _dbus_strdup (send_interface);
rule->d.send.member = _dbus_strdup (send_member);
rule->d.send.error = _dbus_strdup (send_error);
rule->d.send.destination = _dbus_strdup (send_destination);
if (send_destination)
{
rule->d.send.destination = _dbus_strdup (send_destination);
rule->d.send.destination_is_prefix = 0;
}
else if (send_destination_prefix)
{
rule->d.send.destination = _dbus_strdup (send_destination_prefix);
rule->d.send.destination_is_prefix = 1;
}
rule->d.send.max_fds = max_fds;
rule->d.send.min_fds = min_fds;
@ -1601,7 +1624,7 @@ append_rule_from_element (BusConfigParser *parser,
goto nomem;
if (send_error && rule->d.send.error == NULL)
goto nomem;
if (send_destination && rule->d.send.destination == NULL)
if ((send_destination || send_destination_prefix) && rule->d.send.destination == NULL)
goto nomem;
}
else if (any_receive_attribute)

View file

@ -1446,6 +1446,46 @@ bus_connection_get_n_match_rules (DBusConnection *connection)
return d->n_match_rules;
}
/**
* Checks whether the connection owns any name with a given prefix,
* regardless of whether the type of ownership is primary or queued.
*
* @note A name matches to a prefix if it is equal to the prefix,
* or if it starts with the prefix followed by a dot. This is the same
* rule as the 'own_prefix' checking rule.
*
* @param connection the connection
* @param name_prefix the prefix
* @returns #TRUE if the connection owns at least one name with the prefix,
* regardless of the type of ownership
*/
dbus_bool_t
bus_connection_is_name_owner_by_prefix (DBusConnection *connection,
const char *name_prefix)
{
BusConnectionData *d;
DBusList *link;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
link = _dbus_list_get_first_link (&d->services_owned);
while (link != NULL)
{
BusService *service = link->data;
DBusString str;
_dbus_string_init_const (&str, bus_service_get_name (service));
if (_dbus_string_starts_with_words_c_str (&str, name_prefix, '.'))
return TRUE;
link = _dbus_list_get_next_link (&d->services_owned, link);
}
return FALSE;
}
void
bus_connection_add_owned_service_link (DBusConnection *connection,
DBusList *link)

View file

@ -82,6 +82,10 @@ void bus_connection_send_oom_error (DBusConnection *connection,
void bus_connection_request_headers (DBusConnection *connection,
BusExtraHeaders headers);
/* called by policy.c */
dbus_bool_t bus_connection_is_name_owner_by_prefix (DBusConnection *connection,
const char *name_prefix);
/* called by signals.c */
dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection,
BusMatchRule *rule);

View file

@ -1018,7 +1018,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
}
}
if (rule->d.send.destination != NULL)
if (rule->d.send.destination != NULL && !rule->d.send.destination_is_prefix)
{
/* receiver can be NULL for messages that are sent to the
* message bus itself, we check the strings in that case as
@ -1044,9 +1044,9 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
{
DBusString str;
BusService *service;
_dbus_string_init_const (&str, rule->d.send.destination);
service = bus_registry_lookup (registry, &str);
if (service == NULL)
{
@ -1064,6 +1064,43 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
}
}
if (rule->d.send.destination != NULL && rule->d.send.destination_is_prefix)
{
/* receiver can be NULL - the same as in !send.destination_is_prefix */
if (receiver == NULL)
{
const char *destination = dbus_message_get_destination (message);
DBusString dest_name;
if (destination == NULL)
{
_dbus_verbose (" (policy) skipping rule because message has no dest\n");
continue;
}
_dbus_string_init_const (&dest_name, destination);
if (!_dbus_string_starts_with_words_c_str (&dest_name,
rule->d.send.destination,
'.'))
{
_dbus_verbose (" (policy) skipping rule because message dest doesn't start with %s\n",
rule->d.send.destination);
continue;
}
}
else
{
if (!bus_connection_is_name_owner_by_prefix (receiver,
rule->d.send.destination))
{
_dbus_verbose (" (policy) skipping rule because no dest with prefix %s is owned by receiver\n",
rule->d.send.destination);
continue;
}
}
}
if (rule->d.send.min_fds > 0 ||
rule->d.send.max_fds < DBUS_MAXIMUM_MESSAGE_UNIX_FDS)
{
@ -1341,15 +1378,9 @@ bus_rules_check_can_own (DBusList *rules,
}
else if (rule->d.own.prefix)
{
const char *data;
char next_char;
if (!_dbus_string_starts_with_c_str (service_name,
rule->d.own.service_name))
continue;
data = _dbus_string_get_const_data (service_name);
next_char = data[strlen (rule->d.own.service_name)];
if (next_char != '\0' && next_char != '.')
if (!_dbus_string_starts_with_words_c_str (service_name,
rule->d.own.service_name,
'.'))
continue;
}

View file

@ -76,6 +76,7 @@ struct BusPolicyRule
unsigned int requested_reply : 1;
unsigned int log : 1;
unsigned int broadcast : 2; /**< really a BusPolicyTristate */
unsigned int destination_is_prefix : 1;
} send;
struct

View file

@ -2237,6 +2237,32 @@ _dbus_string_starts_with_c_str (const DBusString *a,
return FALSE;
}
/**
* Checks whether a string starts with the given C string, after which it ends or is separated from
* the rest by a given separator character.
*
* @param a the string
* @param c_str the C string
* @param word_separator the separator
* @returns #TRUE if string starts with it
*/
dbus_bool_t
_dbus_string_starts_with_words_c_str (const DBusString *a,
const char *c_str,
char word_separator)
{
char next_char;
const char *data;
_dbus_assert (c_str != NULL);
if (!_dbus_string_starts_with_c_str (a, c_str))
return FALSE;
data = _dbus_string_get_const_data (a);
next_char = data[strlen (c_str)];
return next_char == '\0' || next_char == word_separator;
}
/**
* Appends a two-character hex digit to a string, where the hex digit
* has the value of the given byte.

View file

@ -338,6 +338,10 @@ dbus_bool_t _dbus_string_starts_with_c_str (const DBusString *a,
dbus_bool_t _dbus_string_ends_with_c_str (const DBusString *a,
const char *c_str);
DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_starts_with_words_c_str (const DBusString *a,
const char *c_str,
char word_separator);
DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_string_pop_line (DBusString *source,
DBusString *dest);
DBUS_PRIVATE_EXPORT

View file

@ -919,6 +919,7 @@ statements, and works just like &lt;deny&gt; but with the inverse meaning.</para
send_error="error_name" | "*"
send_broadcast="true" | "false"
send_destination="name" | "*"
send_destination_prefix="name"
send_type="method_call" | "method_return" | "signal" | "error" | "*"
send_path="/path/name" | "*"
@ -997,6 +998,22 @@ will not work either. As a special case,
(whether it has a destination specified or not), and
<literal>receive_sender="*"</literal> similarly matches any message.</para>
<para>
A <literal>send_destination_prefix</literal> rule opens or closes
the whole namespace for sending. It means that messages may or may not
be sent to the <emphasis>owner</emphasis> of any name matching the prefix, regardless of whether
it is the primary or the queued owner.
In other words, for <literal>&lt;allow send_destination_prefix="a.b"/&gt;</literal>
rule and names "a.b", "a.b.c", and "a.b.c.d" present on the bus, it works the same as
if three separate rules: <literal>&lt;allow send_destination="a.b"/&gt;</literal>,
<literal>&lt;allow send_destination="a.b.c"/&gt;</literal>, and
<literal>&lt;allow send_destination="a.b.c.d"/&gt;</literal> had been defined.
The rules for matching names are the same as in <literal>own_prefix</literal>
(see below): a prefix of "a.b" matches names "a.b" or "a.b.c" or "a.b.c.d", but not "a.bc"
or "a.c". The <literal>send_destination_prefix</literal> attribute cannot be combined
with the <literal>send_destination</literal> attribute in the same rule.
</para>
<para>
Rules with <literal>send_broadcast="true"</literal> match signal messages
with no destination (broadcasts). Rules with

View file

@ -604,6 +604,7 @@ in_data = \
data/valid-config-files/max-replies-per-connection.conf.in \
data/valid-config-files/multi-user.conf.in \
data/valid-config-files/pending-fd-timeout.conf.in \
data/valid-config-files/send-destination-prefix-rules.conf.in \
data/valid-config-files/systemd-activation.conf.in \
data/valid-config-files/tmp-session.conf.in \
data/valid-config-files-system/tmp-session-like-system.conf.in \
@ -687,6 +688,9 @@ static_data = \
data/systemd-activation/com.example.ReceiveDenied.service \
data/systemd-activation/com.example.SendDenied.service \
data/systemd-activation/com.example.SendDeniedByAppArmorName.service \
data/systemd-activation/com.example.SendPrefixDenied.service \
data/systemd-activation/com.example.SendPrefixDenied.internal.service \
data/systemd-activation/com.example.SendPrefixDenied.SendPrefixAllowed.internal.service \
data/systemd-activation/com.example.SystemdActivatable1.service \
data/systemd-activation/com.example.SystemdActivatable2.service \
data/systemd-activation/org.freedesktop.systemd1.service \

View file

@ -0,0 +1,4 @@
[D-BUS Service]
Name=com.example.SendPrefixDenied.SendPrefixAllowed.internal
Exec=/bin/false SendPrefixDenied.SendPrefixAllowed.internal
SystemdService=dbus-com.example.SendPrefixDenied.SendPrefixAllowed.internal.service

View file

@ -0,0 +1,4 @@
[D-BUS Service]
Name=com.example.SendPrefixDenied.internal
Exec=/bin/false SendPrefixDenied.internal
SystemdService=dbus-com.example.SendPrefixDenied.internal.service

View file

@ -0,0 +1,4 @@
[D-BUS Service]
Name=com.example.SendPrefixDenied
Exec=/bin/false SendPrefixDenied
SystemdService=dbus-com.example.SendPrefixDenied.service

View file

@ -0,0 +1,121 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<listen>@TEST_LISTEN@</listen>
<policy context="default">
<allow user="*"/>
<deny own="*"/>
<deny send_type="method_call"/>
<allow send_type="signal"/>
<allow send_requested_reply="true" send_type="method_return"/>
<allow send_requested_reply="true" send_type="error"/>
<allow receive_type="method_call"/>
<allow receive_type="method_return"/>
<allow receive_type="error"/>
<allow receive_type="signal"/>
<allow send_destination="org.freedesktop.DBus"
send_interface="org.freedesktop.DBus" />
</policy>
<policy context="default">
<!-- deny the whole namespace first -->
<deny send_destination_prefix="foo.bar.test"/>
<!-- foo.bar.test.dest_prefix as a base for testing names -->
<allow own_prefix="foo.bar.test.dest_prefix"/>
<!-- abbreviations:
a - allow
d - deny
p - prefix
o - other
f - filler, no meaning, just for longer names
x - it's a trap!
-->
<!-- base allow -->
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap"/>
<!-- a neighbour -->
<allow send_destination="foo.bar.test.dest_prefix.ao"/>
<!-- cut out some part of allowed space -->
<deny send_destination="foo.bar.test.dest_prefix.ap.f1.d"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.ap.f1.dp"/>
<!-- punch holes in the cutout -->
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap.f1.d.ap"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap.f1.dp.ap"/>
<allow send_destination="foo.bar.test.dest_prefix.ap.f1.dp.a"/>
<!-- define something but redefine other way -->
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap.f2.apxdp"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.ap.f2.apxdp.dp"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap.f2.apxdp.dp.ap"/>
<deny send_destination="foo.bar.test.dest_prefix.ap.f2.apxdp.dp.ap.d"/>
<!-- redefine -->
<deny send_destination_prefix="foo.bar.test.dest_prefix.ap.f2.apxdp"/>
<allow send_destination="foo.bar.test.dest_prefix.ap.f2.apxdp.dp.a"/>
<allow send_destination="foo.bar.test.dest_prefix.ap.f2.apxdp.dp.ap.f.a"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap.f2.apxdp.f.f.f.ap"/>
<!-- make something complicated but allow it at the end -->
<deny send_destination_prefix="foo.bar.test.dest_prefix.ap.f3.dpxap"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap.f3.dpxap.ap"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.ap.f3.dpxap.ap.dp"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap.f3.dpxap.ap.dp.ap"/>
<allow send_destination="foo.bar.test.dest_prefix.ap.f3.dpxap.ap.dp.a"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap.f3.dpxap"/>
<!-- base deny -->
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp"/>
<!-- neighbours for base deny -->
<deny send_destination="foo.bar.test.dest_prefix.do"/>
<deny send_destination="foo.bar.test.dest_prefix.do.f"/>
<deny send_destination="foo.bar.test.dest_prefix.do.f.f"/>
<allow send_destination="foo.bar.test.dest_prefix.ao.ao"/>
<!-- cut out some part of allowed space -->
<allow send_destination="foo.bar.test.dest_prefix.dp.f1.a"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.dp.f1.ap"/>
<!-- punch holes in the cutout -->
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp.f1.a.dp"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp.f1.ap.dp"/>
<deny send_destination="foo.bar.test.dest_prefix.dp.f1.ap.d"/>
<!-- define something but redefine other way -->
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp.f2.dpxap"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.dp.f2.dpxap.ap"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp.f2.dpxap.ap.dp"/>
<allow send_destination="foo.bar.test.dest_prefix.dp.f2.dpxap.ap.dp.a"/>
<!-- redefine -->
<allow send_destination_prefix="foo.bar.test.dest_prefix.dp.f2.dpxap"/>
<deny send_destination="foo.bar.test.dest_prefix.dp.f2.dpxap.ap.d"/>
<deny send_destination="foo.bar.test.dest_prefix.dp.f2.dpxap.ap.dp.f.d"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp.f2.dpxap.f.f.f.dp"/>
<!-- make something complicated but deny it at the end -->
<allow send_destination_prefix="foo.bar.test.dest_prefix.dp.f3.apxdp"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp.f3.apxdp.dp"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.dp.f3.apxdp.dp.ap"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp.f3.apxdp.dp.ap.dp"/>
<deny send_destination="foo.bar.test.dest_prefix.dp.f3.apxdp.dp.ap.d"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp.f3.apxdp"/>
<!-- test send_destination_prefix with interface and method -->
<deny send_destination_prefix="foo.bar.test.dest_prefix.ap.m"
send_interface="foo.bar.a" send_member="CallDeny"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.ap.m"
send_interface="foo.bar.d"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.ap.m"
send_interface="foo.bar.d" send_member="CallAllow"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.dp.m"
send_interface="foo.bar.a"/>
<deny send_destination_prefix="foo.bar.test.dest_prefix.dp.m"
send_interface="foo.bar.a" send_member="CallDeny"/>
<allow send_destination_prefix="foo.bar.test.dest_prefix.dp.m"
send_interface="foo.bar.d" send_member="CallAllow"/>
</policy>
</busconfig>
<!-- vim: set ft=xml: -->

View file

@ -14,6 +14,8 @@
<policy context="mandatory">
<deny send_destination="com.example.SendDenied"/>
<deny send_destination_prefix="com.example.SendPrefixDenied"/>
<deny receive_interface="com.example.ReceiveDenied" receive_member="Call"/>
<allow send_destination_prefix="com.example.SendPrefixDenied.SendPrefixAllowed"/>
</policy>
</busconfig>

View file

@ -2265,6 +2265,267 @@ test_system_signals (Fixture *f,
#endif
#endif
static void
take_well_known_name (DBusConnection *conn,
const char *name,
DBusError *error,
int ownership_type)
{
int ret = dbus_bus_request_name (conn, name, 0, error);
test_assert_no_error (error);
g_assert_cmpint (ret, ==, ownership_type);
}
static void
drop_well_known_name (DBusConnection *conn,
const char *name,
DBusError *error)
{
int ret = dbus_bus_release_name (conn, name, error);
test_assert_no_error (error);
g_assert_cmpint (ret, ==, DBUS_RELEASE_NAME_REPLY_RELEASED);
}
static void
helper_send_destination_prefix_check (Fixture *f,
const char *name,
const char *interface,
const char *member,
dbus_bool_t allowed,
const char *additional_name,
int ownership_type)
{
DBusMessage *call = NULL;
DBusMessage *reply = NULL;
take_well_known_name (f->right_conn, name, &f->e, ownership_type);
if (additional_name)
take_well_known_name (f->right_conn, additional_name, &f->e, ownership_type);
call = dbus_message_new_method_call (dbus_bus_get_unique_name (f->right_conn),
"/",
interface,
member);
if (call == NULL)
g_error ("OOM");
reply = test_main_context_call_and_wait (f->ctx, f->left_conn, call,
DBUS_TIMEOUT_USE_DEFAULT);
dbus_clear_message (&call);
g_test_message ("reply from %s(%d):%s OK", name, ownership_type, member);
if (allowed)
{
g_test_message ("checking reply from %s for correct method_return", name);
g_assert_cmpint (dbus_message_get_type (reply), ==,
DBUS_MESSAGE_TYPE_METHOD_RETURN);
}
else
{
g_test_message ("checking reply from %s for correct access_denied", name);
g_assert_cmpint (dbus_message_get_type (reply), ==,
DBUS_MESSAGE_TYPE_ERROR);
g_assert_cmpstr (dbus_message_get_error_name (reply), ==,
DBUS_ERROR_ACCESS_DENIED);
}
dbus_clear_message (&reply);
drop_well_known_name (f->right_conn, name, &f->e);
if (additional_name)
drop_well_known_name (f->right_conn, additional_name, &f->e);
}
static void
helper_send_destination_prefix (Fixture *f,
const char *name,
const char *interface,
const char *member,
dbus_bool_t allowed,
const char *additional_name)
{
/* check with primary ownership */
helper_send_destination_prefix_check (f, name, interface, member, allowed, additional_name, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
/* check with queued ownership */
take_well_known_name (f->left_conn, name, &f->e, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
if (additional_name)
take_well_known_name (f->left_conn, additional_name, &f->e, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
helper_send_destination_prefix_check (f, name, interface, member, allowed, additional_name, DBUS_REQUEST_NAME_REPLY_IN_QUEUE);
drop_well_known_name (f->left_conn, name, &f->e);
if (additional_name)
drop_well_known_name (f->left_conn, additional_name, &f->e);
}
static void
test_send_destination_prefix (Fixture *f,
gconstpointer context G_GNUC_UNUSED)
{
if (f->skip)
return;
add_echo_filter (f);
/*
* Names are constructed with prefix foo.bar.test.dest_prefix followed by some of the tokens:
* - a - allow send_destination for this name
* - d - deny send_destination for this name
* - ap - allow send_destination_prefix for this name
* - dp - deny send_destination_prefix for this name
* - f, f1, f2, f3 - fillers for generating names down the name hierarchy
* - apf, dpf, ao, do - just some neighbour names
* - m - names with 'm' have rules for interface and member
* - apxdp, dpxap - names that have contradicting rules, e.g. for apxdp there are "allow send_destination_prefix"
* rules first, followed by "deny send_destination_prefix" rules
*/
/* basic checks - base allow */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.apf", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.apf.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
/* basic checks - base deny */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dpf", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dpf.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
/* With interface and method in the policy:
* everything is allowed, except foo.bar.a.CallDeny and whole foo.bar.d minus foo.bar.d.CallAllow.*/
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m", "foo.bar.a", "CallDeny", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m", "foo.bar.a", "CallAllow", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m", "foo.bar.a", "NonExistent", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m", "foo.bar.d", "CallDeny", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m", "foo.bar.d", "CallAllow", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m", "foo.bar.d", "NonExistent", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m", "foo.bar.none", "NonExistent", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m.f.f.f.f.f", "foo.bar.a", "CallDeny", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m.f.f.f.f.f", "foo.bar.a", "CallAllow", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m.f.f.f.f.f", "foo.bar.a", "NonExistent", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m.f.f.f.f.f", "foo.bar.d", "CallDeny", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m.f.f.f.f.f", "foo.bar.d", "CallAllow", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m.f.f.f.f.f", "foo.bar.d", "NonExistent", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.m.f.f.f.f.f", "foo.bar.none", "NonExistent", TRUE, NULL);
/* With interface and method in the policy:
* everything is denied, except foo.bar.d.CallAllow and whole foo.bar.a minus foo.bar.a.CallDeny */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m", "foo.bar.a", "CallDeny", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m", "foo.bar.a", "CallAllow", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m", "foo.bar.a", "NonExistent", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m", "foo.bar.d", "CallDeny", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m", "foo.bar.d", "CallAllow", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m", "foo.bar.d", "NonExistent", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m", "foo.bar.none", "NonExistent", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m.f.f.f.f.f", "foo.bar.a", "CallDeny", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m.f.f.f.f.f", "foo.bar.a", "CallAllow", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m.f.f.f.f.f", "foo.bar.a", "NonExistent", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m.f.f.f.f.f", "foo.bar.d", "CallDeny", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m.f.f.f.f.f", "foo.bar.d", "CallAllow", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m.f.f.f.f.f", "foo.bar.d", "NonExistent", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.m.f.f.f.f.f", "foo.bar.none", "NonExistent", FALSE, NULL);
/* multiple names owned - everything is allowed */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ao", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.ap.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.ao");
/* multiple names owned - mixed allow/deny, but denied wins */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.ap.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.dp.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.do", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.ap.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.do");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ao", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.dp.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.ao");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.ao.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ao.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.dp.f.f");
/* multiple names owned - mixed allow/deny, but allowed wins */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.ao.ao");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ao.ao", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.dp.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.dp.f1.ap.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap.f", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.dp.f");
/* multiple names owned - everything is denied */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.do.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.do.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.dp.f");
/* holes in default allow */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.d", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.dp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.dp.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.dp.f.f.f.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.ao");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.dp.f.f.f.f", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.ap");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ao", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.ap.f1.dp.f.f.f.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap", "com.example.Anything", "Anything", FALSE, "foo.bar.test.dest_prefix.ap.f1.dp.f.f.f.f");
/* holes in holes in default allow */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.d.ap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.d.ap.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.dp.ap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.dp.ap.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f1.dp.ap.a", "com.example.Anything", "Anything", TRUE, NULL);
/* redefinitions in default allow */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.dp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.dp.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.dp.ap", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.dp.ap.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.dp.ap.d", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.dp.a", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.dp.ap.f.a", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.f.f.f.ap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f2.apxdp.f.f.f.ap.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
/* cancelled definitions in default allow */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f3.dpxap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f3.dpxap.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f3.dpxap.ap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f3.dpxap.ap.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f3.dpxap.ap.dp", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f3.dpxap.ap.dp.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f3.dpxap.ap.dp.ap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f3.dpxap.ap.dp.ap.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ap.f3.dpxap.ap.dp.a", "com.example.Anything", "Anything", TRUE, NULL);
/* holes in default deny */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.a", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.a.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap.f.f.f", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.do");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.do", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.dp.f1.ap.f.f.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap.f.f.f", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.do.f.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.do.f.f", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.dp.f1.ap.f.f.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap.f.f", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.dp.f.f.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f.f.f", "com.example.Anything", "Anything", TRUE, "foo.bar.test.dest_prefix.dp.f1.ap.f.f");
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.ao", "com.example.Anything", "Anything", TRUE, NULL);
/* holes in holes in default deny */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.a.dp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.a.dp.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap.dp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap.dp.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap.d", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f1.ap.d.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
/* redefinitions in default deny */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.ap", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.ap.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.ap.dp", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.ap.dp.f.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.ap.dp.a", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.ap.dp.a.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.ap.d", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.ap.d.f.f.f", "com.example.Anything", "Anything", TRUE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.ap.dp.f.d", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.f.f.f.dp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f2.dpxap.f.f.f.dp.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
/* cancelled definitions in default deny */
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp.dp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp.dp.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp.dp.ap", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp.dp.ap.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp.dp.ap.dp", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp.dp.ap.dp.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp.dp.ap.d", "com.example.Anything", "Anything", FALSE, NULL);
helper_send_destination_prefix (f, "foo.bar.test.dest_prefix.dp.f3.apxdp.dp.ap.d.f.f.f.f", "com.example.Anything", "Anything", FALSE, NULL);
}
static void
teardown (Fixture *f,
gconstpointer context G_GNUC_UNUSED)
@ -2408,6 +2669,11 @@ static Config nearly_system_config = {
#endif
#endif
static Config send_destination_prefix_config = {
NULL, 1, "valid-config-files/send-destination-prefix-rules.conf",
TEST_USER_ME, SPECIFY_ADDRESS
};
int
main (int argc,
char **argv)
@ -2498,6 +2764,9 @@ main (int argc,
#endif
#endif
g_test_add ("/system-policy/send-destination/prefix", Fixture, &send_destination_prefix_config,
setup, test_send_destination_prefix, teardown);
ret = g_test_run ();
dbus_shutdown ();
return ret;

View file

@ -516,6 +516,37 @@ test_activation (Fixture *f,
g_error ("OOM");
dbus_connection_send (f->systemd, m, NULL);
dbus_message_unref (m);
/* A fourth activation: for name from send_destination_prefix namespace */
m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal4");
if (!dbus_message_set_destination (m, "com.example.SendPrefixDenied.SendPrefixAllowed.internal"))
g_error ("OOM");
dbus_connection_send (f->caller, m, NULL);
dbus_message_unref (m);
/* systemd is already ready for it. */
while (f->systemd_message == NULL)
test_main_context_iterate (f->ctx, TRUE);
m = f->systemd_message;
f->systemd_message = NULL;
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
"org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
"org.freedesktop.systemd1");
/* Check ActivationRequest for the required name. */
/* If it is correct, then it passed through policy checking, and the test is over. */
do
{
const char *name;
DBusError error;
dbus_error_init (&error);
dbus_message_get_args (m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
test_assert_no_error (&error);
g_assert_cmpstr (name, ==, "dbus-com.example.SendPrefixDenied.SendPrefixAllowed.internal.service");
} while (0);
dbus_message_unref (m);
}
static void
@ -1031,7 +1062,9 @@ static const Config deny_send_tests[] =
{ "com.example.SendDeniedByNonexistentAppArmorLabel" },
{ "com.example.SendDeniedByAppArmorName" },
#endif
{ "com.example.SendDenied" }
{ "com.example.SendDenied" },
{ "com.example.SendPrefixDenied" },
{ "com.example.SendPrefixDenied.internal" }
};
static const Config deny_receive_tests[] =