From f9c8903a2c1df25f3c0093e57d9f08578a63fce1 Mon Sep 17 00:00:00 2001 From: Adrian Szyndela Date: Wed, 28 Nov 2018 15:15:16 +0100 Subject: [PATCH] dbus-daemon: add send_destination_prefix support Change-Id: Iaa1eff400c045ec46465f248e8460c97bb183e5b --- bus/config-parser.c | 35 +++++++++++++--- bus/connection.c | 27 ++++++++++++ bus/connection.h | 3 ++ bus/policy.c | 115 +++++++++++++++++++++++++++++++++------------------- bus/policy.h | 1 + dbus/dbus-string.c | 26 ++++++++++++ dbus/dbus-string.h | 4 ++ 7 files changed, 164 insertions(+), 47 deletions(-) diff --git a/bus/config-parser.c b/bus/config-parser.c index cb37c7b..00005cc 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -1180,6 +1180,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 *receive_interface; @@ -1207,6 +1208,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, "receive_interface", &receive_interface, @@ -1227,7 +1229,8 @@ append_rule_from_element (BusConfigParser *parser, 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 || @@ -1281,7 +1284,8 @@ append_rule_from_element (BusConfigParser *parser, * 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 @@ -1318,7 +1322,8 @@ append_rule_from_element (BusConfigParser *parser, user || group)) || - (send_destination && (receive_interface || + (send_destination && (send_destination_prefix || + receive_interface || receive_member || receive_error || receive_sender || @@ -1327,6 +1332,15 @@ append_rule_from_element (BusConfigParser *parser, 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 || @@ -1395,7 +1409,7 @@ append_rule_from_element (BusConfigParser *parser, */ #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; @@ -1464,7 +1478,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_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) @@ -1473,7 +1496,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 (receive_interface || receive_member || receive_error || receive_sender || diff --git a/bus/connection.c b/bus/connection.c index b4a2995..aafc520 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -1458,6 +1458,33 @@ bus_connection_get_n_match_rules (DBusConnection *connection) 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) diff --git a/bus/connection.h b/bus/connection.h index 46e883e..6c6fca8 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -98,6 +98,9 @@ dbus_bool_t bus_connection_replace_deferred_message (DBusConnection *con 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, diff --git a/bus/policy.c b/bus/policy.c index 3d4f547..1990621 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -1003,46 +1003,85 @@ bus_client_policy_check_can_send (DBusConnection *sender, 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; + } } } } @@ -1365,15 +1404,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; } diff --git a/bus/policy.h b/bus/policy.h index 1f23431..d80c775 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -75,6 +75,7 @@ struct BusPolicyRule unsigned int eavesdrop : 1; unsigned int requested_reply : 1; unsigned int log : 1; + unsigned int destination_prefix : 1; } send; struct diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 98d9f2b..7a7bd8f 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -2214,6 +2214,32 @@ _dbus_string_starts_with_c_str (const DBusString *a, } /** + * 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. * diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index adf709b..388e762 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -319,6 +319,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 -- 2.7.4