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 *receive_interface;
"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,
"receive_interface", &receive_interface,
NULL))
return FALSE;
- if (!(send_interface || send_member || send_error || send_destination ||
+ if (!(send_interface || send_member || send_error ||
+ send_destination || send_destination_prefix ||
send_type || send_path ||
receive_interface || receive_member || receive_error || receive_sender ||
receive_type || receive_path || eavesdrop ||
* interface + member
* error
*
- * base send_ can combine with send_destination, send_path, send_type, send_requested_reply
+ * base send_ can combine with send_destination, send_destination_prefix, send_path, send_type, send_requested_reply
+ * 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
user ||
group)) ||
- (send_destination && (receive_interface ||
+ (send_destination && (send_destination_prefix ||
+ receive_interface ||
receive_member ||
receive_error ||
receive_sender ||
user ||
group)) ||
+ (send_destination_prefix && (receive_interface ||
+ receive_member ||
+ receive_error ||
+ receive_sender ||
+ receive_requested_reply ||
+ own || own_prefix ||
+ user ||
+ group)) ||
+
(send_type && (receive_interface ||
receive_member ||
receive_error ||
*/
#define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
- if (send_interface || send_member || send_error || send_destination ||
+ if (send_interface || send_member || send_error || send_destination || send_destination_prefix ||
send_path || send_type || send_requested_reply)
{
int message_type;
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_prefix = 0;
+ }
+ else if (send_destination_prefix)
+ {
+ rule->d.send.destination = _dbus_strdup (send_destination_prefix);
+ rule->d.send.destination_prefix = 1;
+ }
if (send_path && rule->d.send.path == NULL)
goto nomem;
if (send_interface && rule->d.send.interface == NULL)
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 (receive_interface || receive_member || receive_error || receive_sender ||
return d->n_match_rules;
}
+dbus_bool_t
+bus_connection_is_service_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)
void bus_connection_dispatch_deferred (DBusConnection *connection);
void bus_connection_clear_deferred_messages (DBusConnection *connection);
+/* called by policy.c */
+dbus_bool_t bus_connection_is_service_owner_by_prefix (DBusConnection *connection,
+ const char *name_prefix);
/* called by signals.c */
dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection,
if (rule->d.send.destination != NULL)
{
- /* receiver can be NULL for messages that are sent to the
- * message bus itself, we check the strings in that case as
- * built-in services don't have a DBusConnection but messages
- * to them have a destination service name.
- *
- * Similarly, receiver can be NULL when we're deciding whether
- * activation should be allowed; we make the authorization decision
- * on the assumption that the activated service will have the
- * requested name and no others.
- */
- if (receiver == NULL)
+ if (!rule->d.send.destination_prefix)
{
- if (!dbus_message_has_destination (message,
- rule->d.send.destination))
+ /* receiver can be NULL for messages that are sent to the
+ * message bus itself, we check the strings in that case as
+ * built-in services don't have a DBusConnection but messages
+ * to them have a destination service name.
+ *
+ * Similarly, receiver can be NULL when we're deciding whether
+ * activation should be allowed; we make the authorization decision
+ * on the assumption that the activated service will have the
+ * requested name and no others.
+ */
+ if (receiver == NULL)
{
- _dbus_verbose (" (policy) skipping rule because message dest is not %s\n",
- rule->d.send.destination);
- continue;
+ if (!dbus_message_has_destination (message,
+ rule->d.send.destination))
+ {
+ _dbus_verbose (" (policy) skipping rule because message dest is not %s\n",
+ rule->d.send.destination);
+ continue;
+ }
+ }
+ else
+ {
+ DBusString str;
+ BusService *service;
+
+ _dbus_string_init_const (&str, rule->d.send.destination);
+
+ service = bus_registry_lookup (registry, &str);
+ if (service == NULL)
+ {
+ _dbus_verbose (" (policy) skipping rule because dest %s doesn't exist\n",
+ rule->d.send.destination);
+ continue;
+ }
+
+ if (!bus_service_has_owner (service, receiver))
+ {
+ _dbus_verbose (" (policy) skipping rule because dest %s isn't owned by receiver\n",
+ rule->d.send.destination);
+ continue;
+ }
}
}
- else
+ else if (rule->d.send.destination_prefix)
{
- DBusString str;
- BusService *service;
-
- _dbus_string_init_const (&str, rule->d.send.destination);
-
- service = bus_registry_lookup (registry, &str);
- if (service == NULL)
+ /* receiver can be NULL - the same as in !send.destination_prefix */
+ if (receiver == NULL)
{
- _dbus_verbose (" (policy) skipping rule because dest %s doesn't exist\n",
- rule->d.send.destination);
- continue;
+ 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;
+ }
}
-
- if (!bus_service_has_owner (service, receiver))
+ else
{
- _dbus_verbose (" (policy) skipping rule because dest %s isn't owned by receiver\n",
- rule->d.send.destination);
- continue;
+ if (!bus_connection_is_service_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;
+ }
}
}
}
}
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;
}
unsigned int eavesdrop : 1;
unsigned int requested_reply : 1;
unsigned int log : 1;
+ unsigned int destination_prefix : 1;
} send;
struct
}
/**
+ * 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.
*
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