From a683a80c409cc4f2e57ba6a3e60d52f91b8657d0 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 21 Sep 2003 19:53:56 +0000 Subject: 2003-09-21 Havoc Pennington Get matching rules mostly working in the bus; only actually parsing the rule text remains. However, the client side of "signal connections" hasn't been started, this patch is only the bus side. * dbus/dispatch.c: fix for the matching rules changes * bus/driver.c (bus_driver_handle_remove_match) (bus_driver_handle_add_match): send an ack reply from these method calls * glib/dbus-gproxy.c (dbus_gproxy_begin_call): fix order of arguments, reported by Seth Nickell * bus/config-parser.c (append_rule_from_element): support eavesdrop=true|false attribute on policies so match rules can be prevented from snooping on the system bus. * bus/dbus-daemon-1.1.in: consistently use terminology "sender" and "destination" in attribute names; fix some docs bugs; add eavesdrop=true|false attribute * bus/driver.c (bus_driver_handle_add_match) (bus_driver_handle_remove_match): handle AddMatch, RemoveMatch messages * dbus/dbus-protocol.h (DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST): get rid of broadcast service concept, signals are just always broadcast * bus/signals.c, bus/dispatch.c, bus/connection.c, bus/bus.c: mostly implement matching rules stuff (currently only exposed as signal connections) --- bus/Makefile.am | 2 + bus/bus.c | 65 ++++- bus/bus.h | 71 ++--- bus/config-parser.c | 102 ++++--- bus/connection.c | 123 +++++++- bus/connection.h | 13 +- bus/dbus-daemon-1.1.in | 49 ++-- bus/dispatch.c | 312 +++++++++++++++----- bus/dispatch.h | 3 +- bus/driver.c | 164 ++++++++++- bus/policy.c | 39 ++- bus/policy.h | 3 + bus/session.conf.in | 5 +- bus/signals.c | 774 +++++++++++++++++++++++++++++++++++++++++++++++++ bus/signals.h | 83 ++++++ bus/system.conf.in | 4 +- bus/test-main.c | 6 + bus/test.h | 1 + 18 files changed, 1635 insertions(+), 184 deletions(-) create mode 100644 bus/signals.c create mode 100644 bus/signals.h (limited to 'bus') diff --git a/bus/Makefile.am b/bus/Makefile.am index 27735077..bc728801 100644 --- a/bus/Makefile.am +++ b/bus/Makefile.am @@ -44,6 +44,8 @@ BUS_SOURCES= \ policy.h \ services.c \ services.h \ + signals.c \ + signals.h \ test.c \ test.h \ utils.c \ diff --git a/bus/bus.c b/bus/bus.c index 1b461fe3..4087334e 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -28,6 +28,7 @@ #include "utils.h" #include "policy.h" #include "config-parser.h" +#include "signals.h" #include #include #include @@ -44,6 +45,7 @@ struct BusContext BusActivation *activation; BusRegistry *registry; BusPolicy *policy; + BusMatchmaker *matchmaker; DBusUserDatabase *user_database; BusLimits limits; }; @@ -505,6 +507,13 @@ bus_context_new (const DBusString *config_file, goto failed; } + context->matchmaker = bus_matchmaker_new (); + if (context->matchmaker == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + context->policy = bus_config_parser_steal_policy (parser); _dbus_assert (context->policy != NULL); @@ -715,6 +724,12 @@ bus_context_unref (BusContext *context) _dbus_loop_unref (context->loop); context->loop = NULL; } + + if (context->matchmaker) + { + bus_matchmaker_unref (context->matchmaker); + context->matchmaker = NULL; + } dbus_free (context->type); dbus_free (context->address); @@ -771,6 +786,12 @@ bus_context_get_activation (BusContext *context) return context->activation; } +BusMatchmaker* +bus_context_get_matchmaker (BusContext *context) +{ + return context->matchmaker; +} + DBusLoop* bus_context_get_loop (BusContext *context) { @@ -845,18 +866,33 @@ bus_context_get_max_services_per_connection (BusContext *context) return context->limits.max_services_per_connection; } +int +bus_context_get_max_match_rules_per_connection (BusContext *context) +{ + return context->limits.max_match_rules_per_connection; +} + dbus_bool_t bus_context_check_security_policy (BusContext *context, DBusConnection *sender, - DBusConnection *recipient, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, DBusMessage *message, DBusError *error) { BusClientPolicy *sender_policy; BusClientPolicy *recipient_policy; - /* NULL sender/receiver means the bus driver */ + /* NULL sender, proposed_recipient means the bus driver. NULL + * addressed_recipient means the message didn't specify an explicit + * target. If proposed_recipient is NULL, then addressed_recipient + * is also NULL but is implicitly the bus driver. + */ + _dbus_assert (proposed_recipient == NULL || + (dbus_message_get_destination (message) == NULL || + addressed_recipient != NULL)); + if (sender != NULL) { if (bus_connection_is_active (sender)) @@ -869,7 +905,7 @@ bus_context_check_security_policy (BusContext *context, /* Policy for inactive connections is that they can only send * the hello message to the bus driver */ - if (recipient == NULL && + if (proposed_recipient == NULL && dbus_message_is_method_call (message, DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, "Hello")) @@ -897,15 +933,15 @@ bus_context_check_security_policy (BusContext *context, _dbus_assert ((sender != NULL && sender_policy != NULL) || (sender == NULL && sender_policy == NULL)); - if (recipient != NULL) + if (proposed_recipient != NULL) { /* only the bus driver can send to an inactive recipient (as it * owns no services, so other apps can't address it). Inactive * recipients can receive any message. */ - if (bus_connection_is_active (recipient)) + if (bus_connection_is_active (proposed_recipient)) { - recipient_policy = bus_connection_get_policy (recipient); + recipient_policy = bus_connection_get_policy (proposed_recipient); _dbus_assert (recipient_policy != NULL); } else if (sender == NULL) @@ -922,13 +958,13 @@ bus_context_check_security_policy (BusContext *context, else recipient_policy = NULL; - _dbus_assert ((recipient != NULL && recipient_policy != NULL) || - (recipient != NULL && sender == NULL && recipient_policy == NULL) || - (recipient == NULL && recipient_policy == NULL)); + _dbus_assert ((proposed_recipient != NULL && recipient_policy != NULL) || + (proposed_recipient != NULL && sender == NULL && recipient_policy == NULL) || + (proposed_recipient == NULL && recipient_policy == NULL)); if (sender_policy && !bus_client_policy_check_can_send (sender_policy, - context->registry, recipient, + context->registry, proposed_recipient, message)) { const char *dest = dbus_message_get_destination (message); @@ -951,6 +987,7 @@ bus_context_check_security_policy (BusContext *context, if (recipient_policy && !bus_client_policy_check_can_receive (recipient_policy, context->registry, sender, + addressed_recipient, proposed_recipient, message)) { const char *dest = dbus_message_get_destination (message); @@ -971,14 +1008,16 @@ bus_context_check_security_policy (BusContext *context, } /* See if limits on size have been exceeded */ - if (recipient && - dbus_connection_get_outgoing_size (recipient) > + if (proposed_recipient && + dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) { const char *dest = dbus_message_get_destination (message); dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "The destination service \"%s\" has a full message queue", - dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + dest ? dest : (proposed_recipient ? + bus_connection_get_name (proposed_recipient) : + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)); _dbus_verbose ("security policy disallowing message due to full message queue\n"); return FALSE; } diff --git a/bus/bus.h b/bus/bus.h index 8f32d7a9..5809321a 100644 --- a/bus/bus.h +++ b/bus/bus.h @@ -40,7 +40,8 @@ typedef struct BusPolicyRule BusPolicyRule; typedef struct BusRegistry BusRegistry; typedef struct BusService BusService; typedef struct BusTransaction BusTransaction; - +typedef struct BusMatchmaker BusMatchmaker; +typedef struct BusMatchRule BusMatchRule; typedef struct { @@ -54,40 +55,44 @@ typedef struct int max_connections_per_user; /**< Max number of connections auth'd as same user */ int max_pending_activations; /**< Max number of pending activations for the entire bus */ int max_services_per_connection; /**< Max number of owned services for a single connection */ + int max_match_rules_per_connection; /**< Max number of match rules for a single connection */ } BusLimits; -BusContext* bus_context_new (const DBusString *config_file, - dbus_bool_t force_fork, - int print_addr_fd, - int print_pid_fd, - DBusError *error); -void bus_context_shutdown (BusContext *context); -void bus_context_ref (BusContext *context); -void bus_context_unref (BusContext *context); -const char* bus_context_get_type (BusContext *context); -const char* bus_context_get_address (BusContext *context); -BusRegistry* bus_context_get_registry (BusContext *context); -BusConnections* bus_context_get_connections (BusContext *context); -BusActivation* bus_context_get_activation (BusContext *context); -DBusLoop* bus_context_get_loop (BusContext *context); -DBusUserDatabase* bus_context_get_user_database (BusContext *context); -dbus_bool_t bus_context_allow_user (BusContext *context, - unsigned long uid); -BusClientPolicy* bus_context_create_client_policy (BusContext *context, - DBusConnection *connection, - DBusError *error); +BusContext* bus_context_new (const DBusString *config_file, + dbus_bool_t force_fork, + int print_addr_fd, + int print_pid_fd, + DBusError *error); +void bus_context_shutdown (BusContext *context); +void bus_context_ref (BusContext *context); +void bus_context_unref (BusContext *context); +const char* bus_context_get_type (BusContext *context); +const char* bus_context_get_address (BusContext *context); +BusRegistry* bus_context_get_registry (BusContext *context); +BusConnections* bus_context_get_connections (BusContext *context); +BusActivation* bus_context_get_activation (BusContext *context); +BusMatchmaker* bus_context_get_matchmaker (BusContext *context); +DBusLoop* bus_context_get_loop (BusContext *context); +DBusUserDatabase* bus_context_get_user_database (BusContext *context); +dbus_bool_t bus_context_allow_user (BusContext *context, + unsigned long uid); +BusClientPolicy* bus_context_create_client_policy (BusContext *context, + DBusConnection *connection, + DBusError *error); +int bus_context_get_activation_timeout (BusContext *context); +int bus_context_get_auth_timeout (BusContext *context); +int bus_context_get_max_completed_connections (BusContext *context); +int bus_context_get_max_incomplete_connections (BusContext *context); +int bus_context_get_max_connections_per_user (BusContext *context); +int bus_context_get_max_pending_activations (BusContext *context); +int bus_context_get_max_services_per_connection (BusContext *context); +int bus_context_get_max_match_rules_per_connection (BusContext *context); +dbus_bool_t bus_context_check_security_policy (BusContext *context, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, + DBusMessage *message, + DBusError *error); -int bus_context_get_activation_timeout (BusContext *context); -int bus_context_get_auth_timeout (BusContext *context); -int bus_context_get_max_completed_connections (BusContext *context); -int bus_context_get_max_incomplete_connections (BusContext *context); -int bus_context_get_max_connections_per_user (BusContext *context); -int bus_context_get_max_pending_activations (BusContext *context); -int bus_context_get_max_services_per_connection (BusContext *context); -dbus_bool_t bus_context_check_security_policy (BusContext *context, - DBusConnection *sender, - DBusConnection *recipient, - DBusMessage *message, - DBusError *error); #endif /* BUS_BUS_H */ diff --git a/bus/config-parser.c b/bus/config-parser.c index cbc239f9..7b9b962d 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -334,6 +334,8 @@ bus_config_parser_new (const DBusString *basedir, parser->limits.max_pending_activations = 256; parser->limits.max_services_per_connection = 256; + + parser->limits.max_match_rules_per_connection = 128; parser->refcount = 1; @@ -837,15 +839,16 @@ append_rule_from_element (BusConfigParser *parser, const char *send_interface; const char *send_member; const char *send_error; - const char *send_service; + const char *send_destination; const char *send_path; const char *send_type; const char *receive_interface; const char *receive_member; const char *receive_error; - const char *receive_service; + const char *receive_sender; const char *receive_path; const char *receive_type; + const char *eavesdrop; const char *own; const char *user; const char *group; @@ -858,25 +861,26 @@ append_rule_from_element (BusConfigParser *parser, "send_interface", &send_interface, "send_member", &send_member, "send_error", &send_error, - "send_service", &send_service, + "send_destination", &send_destination, "send_path", &send_path, "send_type", &send_type, "receive_interface", &receive_interface, "receive_member", &receive_member, "receive_error", &receive_error, - "receive_service", &receive_service, + "receive_sender", &receive_sender, "receive_path", &receive_path, "receive_type", &receive_type, + "eavesdrop", &eavesdrop, "own", &own, "user", &user, "group", &group, NULL)) return FALSE; - if (!(send_interface || send_member || send_error || send_service || + if (!(send_interface || send_member || send_error || send_destination || send_type || send_path || - receive_interface || receive_member || receive_error || receive_service || - receive_type || receive_path || + receive_interface || receive_member || receive_error || receive_sender || + receive_type || receive_path || eavesdrop || own || user || group)) { dbus_set_error (error, DBUS_ERROR_FAILED, @@ -902,17 +906,20 @@ append_rule_from_element (BusConfigParser *parser, * interface + member * error * - * base send_ can combine with send_service, send_path, send_type - * base receive_ with receive_service, receive_path, receive_type + * base send_ can combine with send_destination, send_path, send_type + * base receive_ with receive_sender, receive_path, receive_type, eavesdrop * * user, group, own must occur alone + * + * Pretty sure the below stuff is broken, FIXME think about it more. */ if (((send_interface && send_error) || (send_interface && receive_interface) || (send_interface && receive_member) || (send_interface && receive_error) || - (send_interface && receive_service) || + (send_interface && receive_sender) || + (send_interface && eavesdrop) || (send_interface && own) || (send_interface && user) || (send_interface && group)) || @@ -921,7 +928,8 @@ append_rule_from_element (BusConfigParser *parser, (send_member && receive_interface) || (send_member && receive_member) || (send_member && receive_error) || - (send_member && receive_service) || + (send_member && receive_sender) || + (send_member && eavesdrop) || (send_member && own) || (send_member && user) || (send_member && group)) || @@ -929,23 +937,26 @@ append_rule_from_element (BusConfigParser *parser, ((send_error && receive_interface) || (send_error && receive_member) || (send_error && receive_error) || - (send_error && receive_service) || + (send_error && receive_sender) || + (send_error && eavesdrop) || (send_error && own) || (send_error && user) || (send_error && group)) || - ((send_service && receive_interface) || - (send_service && receive_member) || - (send_service && receive_error) || - (send_service && receive_service) || - (send_service && own) || - (send_service && user) || - (send_service && group)) || + ((send_destination && receive_interface) || + (send_destination && receive_member) || + (send_destination && receive_error) || + (send_destination && receive_sender) || + (send_destination && eavesdrop) || + (send_destination && own) || + (send_destination && user) || + (send_destination && group)) || ((send_type && receive_interface) || (send_type && receive_member) || (send_type && receive_error) || - (send_type && receive_service) || + (send_type && receive_sender) || + (send_type && eavesdrop) || (send_type && own) || (send_type && user) || (send_type && group)) || @@ -953,7 +964,8 @@ append_rule_from_element (BusConfigParser *parser, ((send_path && receive_interface) || (send_path && receive_member) || (send_path && receive_error) || - (send_path && receive_service) || + (send_path && receive_sender) || + (send_path && eavesdrop) || (send_path && own) || (send_path && user) || (send_path && group)) || @@ -967,19 +979,22 @@ append_rule_from_element (BusConfigParser *parser, (receive_member && own) || (receive_member && user) || (receive_member && group)) || - + ((receive_error && own) || (receive_error && user) || (receive_error && group)) || + ((eavesdrop && own) || + (eavesdrop && user) || + (eavesdrop && group)) || + ((own && user) || (own && group)) || ((user && group))) { dbus_set_error (error, DBUS_ERROR_FAILED, - "Invalid combination of attributes on element <%s>, " - "only send_foo/send_service or receive_foo/receive_service may be paired", + "Invalid combination of attributes on element <%s>", element_name); return FALSE; } @@ -991,7 +1006,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_service || + if (send_interface || send_member || send_error || send_destination || send_path || send_type) { int message_type; @@ -1002,8 +1017,8 @@ append_rule_from_element (BusConfigParser *parser, send_member = NULL; if (IS_WILDCARD (send_error)) send_error = NULL; - if (IS_WILDCARD (send_service)) - send_service = NULL; + if (IS_WILDCARD (send_destination)) + send_destination = NULL; if (IS_WILDCARD (send_path)) send_path = NULL; if (IS_WILDCARD (send_type)) @@ -1025,13 +1040,13 @@ append_rule_from_element (BusConfigParser *parser, rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); if (rule == NULL) goto nomem; - + rule->d.send.message_type = message_type; rule->d.send.path = _dbus_strdup (send_path); 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_service); + rule->d.send.destination = _dbus_strdup (send_destination); if (send_path && rule->d.send.path == NULL) goto nomem; if (send_interface && rule->d.send.interface == NULL) @@ -1040,11 +1055,11 @@ append_rule_from_element (BusConfigParser *parser, goto nomem; if (send_error && rule->d.send.error == NULL) goto nomem; - if (send_service && rule->d.send.destination == NULL) + if (send_destination && rule->d.send.destination == NULL) goto nomem; } - else if (receive_interface || receive_member || receive_error || receive_service || - receive_path || receive_type) + else if (receive_interface || receive_member || receive_error || receive_sender || + receive_path || receive_type || eavesdrop) { int message_type; @@ -1054,14 +1069,13 @@ append_rule_from_element (BusConfigParser *parser, receive_member = NULL; if (IS_WILDCARD (receive_error)) receive_error = NULL; - if (IS_WILDCARD (receive_service)) - receive_service = NULL; + if (IS_WILDCARD (receive_sender)) + receive_sender = NULL; if (IS_WILDCARD (receive_path)) receive_path = NULL; if (IS_WILDCARD (receive_type)) receive_type = NULL; - message_type = DBUS_MESSAGE_TYPE_INVALID; if (receive_type != NULL) { @@ -1074,17 +1088,31 @@ append_rule_from_element (BusConfigParser *parser, return FALSE; } } + + + if (eavesdrop && + !(strcmp (eavesdrop, "true") == 0 || + strcmp (eavesdrop, "false") == 0)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad value \"%s\" for eavesdrop attribute, must be true or false", + eavesdrop); + return FALSE; + } rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); if (rule == NULL) goto nomem; + if (eavesdrop) + rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0); + rule->d.receive.message_type = message_type; rule->d.receive.path = _dbus_strdup (receive_path); rule->d.receive.interface = _dbus_strdup (receive_interface); rule->d.receive.member = _dbus_strdup (receive_member); rule->d.receive.error = _dbus_strdup (receive_error); - rule->d.receive.origin = _dbus_strdup (receive_service); + rule->d.receive.origin = _dbus_strdup (receive_sender); if (receive_path && rule->d.receive.path == NULL) goto nomem; if (receive_interface && rule->d.receive.interface == NULL) @@ -1093,7 +1121,7 @@ append_rule_from_element (BusConfigParser *parser, goto nomem; if (receive_error && rule->d.receive.error == NULL) goto nomem; - if (receive_service && rule->d.receive.origin == NULL) + if (receive_sender && rule->d.receive.origin == NULL) goto nomem; } else if (own) diff --git a/bus/connection.c b/bus/connection.c index f6ce4a29..a824576c 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -25,6 +25,7 @@ #include "policy.h" #include "services.h" #include "utils.h" +#include "signals.h" #include #include #include @@ -41,6 +42,7 @@ struct BusConnections BusContext *context; DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */ DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */ + int stamp; /**< Incrementing number */ }; static dbus_int32_t connection_data_slot = -1; @@ -52,6 +54,8 @@ typedef struct DBusConnection *connection; DBusList *services_owned; int n_services_owned; + DBusList *match_rules; + int n_match_rules; char *name; DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */ DBusMessage *oom_message; @@ -60,6 +64,7 @@ typedef struct long connection_tv_sec; /**< Time when we connected (seconds component) */ long connection_tv_usec; /**< Time when we connected (microsec component) */ + int stamp; /**< connections->stamp last time we were traversed */ } BusConnectionData; static dbus_bool_t expire_incomplete_timeout (void *data); @@ -140,12 +145,20 @@ bus_connection_disconnected (DBusConnection *connection) { BusConnectionData *d; BusService *service; - + BusMatchmaker *matchmaker; + d = BUS_CONNECTION_DATA (connection); _dbus_assert (d != NULL); _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n", d->name ? d->name : "(inactive)"); + + /* Delete our match rules */ + if (d->n_match_rules > 0) + { + matchmaker = bus_context_get_matchmaker (d->connections->context); + bus_matchmaker_disconnected (matchmaker, connection); + } /* Drop any service ownership. FIXME Unfortunately, this requires * memory allocation and there doesn't seem to be a good way to @@ -881,6 +894,40 @@ bus_connections_get_context (BusConnections *connections) return connections->context; } +/* + * This is used to avoid covering the same connection twice when + * traversing connections. Note that it assumes we will + * bus_connection_mark_stamp() each connection at least once per + * INT_MAX increments of the global stamp, or wraparound would break + * things. + */ +void +bus_connections_increment_stamp (BusConnections *connections) +{ + connections->stamp += 1; +} + +/* Mark connection with current stamp, return TRUE if it + * didn't already have that stamp + */ +dbus_bool_t +bus_connection_mark_stamp (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + if (d->stamp == d->connections->stamp) + return FALSE; + else + { + d->stamp = d->connections->stamp; + return TRUE; + } +} + BusContext* bus_connection_get_context (DBusConnection *connection) { @@ -929,6 +976,18 @@ bus_connection_get_activation (DBusConnection *connection) return bus_context_get_activation (d->connections->context); } +BusMatchmaker* +bus_connection_get_matchmaker (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + return bus_context_get_matchmaker (d->connections->context); +} + /** * Checks whether the connection is registered with the message bus. * @@ -1024,6 +1083,62 @@ bus_connection_send_oom_error (DBusConnection *connection, d->oom_preallocated = NULL; } +void +bus_connection_add_match_rule_link (DBusConnection *connection, + DBusList *link) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + _dbus_list_append_link (&d->match_rules, link); + + d->n_match_rules += 1; +} + +dbus_bool_t +bus_connection_add_match_rule (DBusConnection *connection, + BusMatchRule *rule) +{ + DBusList *link; + + link = _dbus_list_alloc_link (rule); + + if (link == NULL) + return FALSE; + + bus_connection_add_match_rule_link (connection, link); + + return TRUE; +} + +void +bus_connection_remove_match_rule (DBusConnection *connection, + BusMatchRule *rule) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + _dbus_list_remove_last (&d->match_rules, rule); + + d->n_match_rules -= 1; + _dbus_assert (d->n_match_rules >= 0); +} + +int +bus_connection_get_n_match_rules (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + return d->n_match_rules; +} + void bus_connection_add_owned_service_link (DBusConnection *connection, DBusList *link) @@ -1092,6 +1207,8 @@ bus_connection_complete (DBusConnection *connection, _dbus_assert (d != NULL); _dbus_assert (d->name == NULL); _dbus_assert (d->policy == NULL); + + _dbus_assert (!bus_connection_is_active (connection)); if (!_dbus_string_copy_data (name, &d->name)) { @@ -1147,6 +1264,8 @@ bus_connection_complete (DBusConnection *connection, /* See if we can remove the timeout */ bus_connections_expire_incomplete (d->connections); + + _dbus_assert (bus_connection_is_active (connection)); return TRUE; } @@ -1327,7 +1446,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction, * eat it; the driver doesn't care about getting a reply. */ if (!bus_context_check_security_policy (bus_transaction_get_context (transaction), - NULL, connection, message, NULL)) + NULL, connection, connection, message, NULL)) return TRUE; return bus_transaction_send (transaction, connection, message); diff --git a/bus/connection.h b/bus/connection.h index 92c93267..d9fd727e 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -44,16 +44,18 @@ void bus_connections_foreach_active (BusConnections BusConnectionForeachFunction function, void *data); BusContext* bus_connections_get_context (BusConnections *connections); +void bus_connections_increment_stamp (BusConnections *connections); BusContext* bus_connection_get_context (DBusConnection *connection); BusConnections* bus_connection_get_connections (DBusConnection *connection); BusRegistry* bus_connection_get_registry (DBusConnection *connection); BusActivation* bus_connection_get_activation (DBusConnection *connection); +BusMatchmaker* bus_connection_get_matchmaker (DBusConnection *connection); dbus_bool_t bus_connections_check_limits (BusConnections *connections, DBusConnection *requesting_completion, DBusError *error); void bus_connections_expire_incomplete (BusConnections *connections); - +dbus_bool_t bus_connection_mark_stamp (DBusConnection *connection); dbus_bool_t bus_connection_is_active (DBusConnection *connection); const char *bus_connection_get_name (DBusConnection *connection); @@ -62,6 +64,15 @@ dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection); void bus_connection_send_oom_error (DBusConnection *connection, DBusMessage *in_reply_to); +/* called by signals.c */ +dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection, + BusMatchRule *rule); +void bus_connection_add_match_rule_link (DBusConnection *connection, + DBusList *link); +void bus_connection_remove_match_rule (DBusConnection *connection, + BusMatchRule *rule); +int bus_connection_get_n_match_rules (DBusConnection *connection); + /* called by services.c */ dbus_bool_t bus_connection_add_owned_service (DBusConnection *connection, diff --git a/bus/dbus-daemon-1.1.in b/bus/dbus-daemon-1.1.in index ec915edd..b272a62e 100644 --- a/bus/dbus-daemon-1.1.in +++ b/bus/dbus-daemon-1.1.in @@ -328,26 +328,32 @@ in the config file. .TP .I "" +.I "" + +.PP +A element appears below a element and prohibits some +action. The element makes an exception to previous +statements, and works just like but with the inverse meaning. .PP -A element appears below a element and prohibits -some action. The possible attributes of a element are: +The possible attributes of these elements are: .nf send_interface="interface_name" send_member="method_or_signal_name" send_error="error_name" - send_service="service_name" - send_type="method_call|method_return|signal|error" + send_destination="service_name" + send_type="method_call" | "method_return" | "signal" | "error" send_path="/path/name" receive_interface="interface_name" receive_member="method_or_signal_name" receive_error="error_name" - receive_service="service_name" - receive_type="method_call|method_return|signal|error" + receive_sender="service_name" + receive_type="method_call" | "method_return" | "signal" | "error" receive_path="/path/name" + + eavesdrop="true" | "false" - receive="messagename" own="servicename" user="username" group="groupname" @@ -359,8 +365,8 @@ Examples: - - + + .fi @@ -371,7 +377,7 @@ particular action. If it matches, the action is denied (unless later rules in the config file allow it). .PP -send_service and receive_service rules mean that messages may not be +send_destination and receive_sender rules mean that messages may not be sent to or received from the *owner* of the given service, not that they may not be sent *to that service name*. That is, if a connection owns services A, B, C, and sending to A is denied, sending to B or C @@ -381,6 +387,22 @@ will not work either. The other send_* and receive_* attributes are purely textual/by-value matches against the given field in the message header. +.PP +"Eavesdropping" occurs when an application receives a message that +was explicitly addressed to a service the application does not own. +Eavesdropping thus only applies to messages that are addressed to +services (i.e. it does not apply to signals). + +.PP +For , eavesdrop="true" indicates that the rule matches even +when eavesdropping. eavesdrop="false" is the default and means that +the rule only allows messages to go to their specified recipient. +For , eavesdrop="true" indicates that the rule matches +only when eavesdropping. eavesdrop="false" is the default for +also, but here it means that the rule applies always, even when +not eavesdropping. The eavesdrop attribute can only be combined with +receive rules (with receive_* attributes). + .PP user and group denials mean that the given user or group may not connect to the message bus. @@ -413,13 +435,6 @@ received" are evaluated separately. Be careful with send_interface/receive_interface, because the interface field in messages is optional. -.TP -.I "" - -.PP -Makes an exception to previous statements. Works -just like but with the inverse meaning. - .SH AUTHOR See http://www.freedesktop.org/software/dbus/doc/AUTHORS diff --git a/bus/dispatch.c b/bus/dispatch.c index 7bdda0d4..606c68ef 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -28,36 +28,33 @@ #include "services.h" #include "utils.h" #include "bus.h" +#include "signals.h" #include "test.h" #include #include -typedef struct -{ - BusContext *context; - DBusConnection *sender; - DBusMessage *message; - BusTransaction *transaction; - DBusError *error; -} SendMessageData; - static dbus_bool_t -send_one_message (DBusConnection *connection, void *data) +send_one_message (DBusConnection *connection, + BusContext *context, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + BusTransaction *transaction, + DBusError *error) { - SendMessageData *d = data; - - if (!bus_context_check_security_policy (d->context, - d->sender, + if (!bus_context_check_security_policy (context, + sender, + addressed_recipient, connection, - d->message, + message, NULL)) return TRUE; /* silently don't send it */ - if (!bus_transaction_send (d->transaction, + if (!bus_transaction_send (transaction, connection, - d->message)) + message)) { - BUS_SET_OOM (d->error); + BUS_SET_OOM (error); return FALSE; } @@ -65,30 +62,60 @@ send_one_message (DBusConnection *connection, void *data) } dbus_bool_t -bus_dispatch_broadcast_message (BusTransaction *transaction, - DBusConnection *sender, - DBusMessage *message, - DBusError *error) +bus_dispatch_matches (BusTransaction *transaction, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + DBusError *error) { DBusError tmp_error; - SendMessageData d; BusConnections *connections; + DBusList *recipients; + BusMatchmaker *matchmaker; + DBusList *link; + BusContext *context; _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + + /* sender and recipient can both be NULL for the bus driver, + * or for signals with no particular recipient + */ + + _dbus_assert (sender == NULL || bus_connection_is_active (sender)); _dbus_assert (dbus_message_get_sender (message) != NULL); connections = bus_transaction_get_connections (transaction); dbus_error_init (&tmp_error); - d.sender = sender; - d.context = bus_transaction_get_context (transaction); - d.message = message; - d.transaction = transaction; - d.error = &tmp_error; - - bus_connections_foreach_active (connections, send_one_message, &d); + context = bus_transaction_get_context (transaction); + matchmaker = bus_context_get_matchmaker (context); + + recipients = NULL; + if (!bus_matchmaker_get_recipients (matchmaker, + bus_context_get_connections (context), + sender, addressed_recipient, message, + &recipients)) + { + BUS_SET_OOM (error); + return FALSE; + } + + link = _dbus_list_get_first_link (&recipients); + while (link != NULL) + { + DBusConnection *dest; + + dest = link->data; + + if (!send_one_message (dest, context, sender, addressed_recipient, + message, transaction, &tmp_error)) + break; + + link = _dbus_list_get_next_link (&recipients, link); + } + _dbus_list_clear (&recipients); + if (dbus_error_is_set (&tmp_error)) { dbus_move_error (&tmp_error, error); @@ -107,10 +134,12 @@ bus_dispatch (DBusConnection *connection, BusTransaction *transaction; BusContext *context; DBusHandlerResult result; - + DBusConnection *addressed_recipient; + result = DBUS_HANDLER_RESULT_HANDLED; transaction = NULL; + addressed_recipient = NULL; dbus_error_init (&error); context = bus_connection_get_context (connection); @@ -143,26 +172,31 @@ bus_dispatch (DBusConnection *connection, } #endif /* DBUS_ENABLE_VERBOSE_MODE */ - /* If service_name is NULL, this is a message to the bus daemon, not - * intended to actually go "on the bus"; e.g. a peer-to-peer + /* If service_name is NULL, if it's a signal we send it to all + * connections with a match rule. If it's not a signal, it goes to + * the bus daemon but doesn't go "on the bus"; e.g. a peer-to-peer * ping. Handle these immediately, especially disconnection * messages. There are no security policy checks on these. */ if (service_name == NULL) - { + { if (dbus_message_is_signal (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, "Disconnected")) - bus_connection_disconnected (connection); + { + bus_connection_disconnected (connection); + goto out; + } - /* DBusConnection also handles some of these automatically, we leave - * it to do so. - */ - result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - goto out; + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL) + { + /* DBusConnection also handles some of these automatically, we leave + * it to do so. + */ + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto out; + } } - - _dbus_assert (service_name != NULL); /* this message is intended for bus routing */ /* Create our transaction */ transaction = bus_transaction_new (context); @@ -191,11 +225,12 @@ bus_dispatch (DBusConnection *connection, */ service_name = dbus_message_get_destination (message); } - - if (strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0) /* to bus driver */ + + if (service_name && + strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0) /* to bus driver */ { if (!bus_context_check_security_policy (context, - connection, NULL, message, &error)) + connection, NULL, NULL, message, &error)) { _dbus_verbose ("Security policy rejected message\n"); goto out; @@ -209,22 +244,16 @@ bus_dispatch (DBusConnection *connection, { _dbus_verbose ("Received message from non-registered client. Disconnecting.\n"); dbus_connection_disconnect (connection); + goto out; } - /* FIXME what if we un-special-case this service and just have a flag - * on services that all service owners will get messages to it, not just - * the primary owner. - */ - else if (strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST) == 0) /* spam! */ - { - if (!bus_dispatch_broadcast_message (transaction, connection, message, &error)) - goto out; - } - else /* route to named service */ + else if (service_name != NULL) /* route to named service */ { DBusString service_string; BusService *service; BusRegistry *registry; + _dbus_assert (service_name != NULL); + registry = bus_connection_get_registry (connection); _dbus_string_init_const (&service_string, service_name); @@ -239,24 +268,30 @@ bus_dispatch (DBusConnection *connection, goto out; } else - { - DBusConnection *recipient; - - recipient = bus_service_get_primary_owner (service); - _dbus_assert (recipient != NULL); + { + addressed_recipient = bus_service_get_primary_owner (service); + _dbus_assert (addressed_recipient != NULL); if (!bus_context_check_security_policy (context, - connection, recipient, message, &error)) + connection, addressed_recipient, + addressed_recipient, + message, &error)) goto out; /* Dispatch the message */ - if (!bus_transaction_send (transaction, recipient, message)) + if (!bus_transaction_send (transaction, addressed_recipient, message)) { BUS_SET_OOM (&error); goto out; } } } + + /* Now match the messages against any match rules, which will send + * out signals and such. addressed_recipient may == NULL. + */ + if (!bus_dispatch_matches (transaction, connection, addressed_recipient, message, &error)) + goto out; out: if (dbus_error_is_set (&error)) @@ -673,7 +708,7 @@ check_hello_message (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; char *name; @@ -684,6 +719,8 @@ check_hello_message (BusContext *context, name = NULL; acquired = NULL; message = NULL; + + _dbus_verbose ("check_hello_message for %p\n", connection); message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, DBUS_PATH_ORG_FREEDESKTOP_DBUS, @@ -791,7 +828,7 @@ check_hello_message (BusContext *context, while (!dbus_bus_set_base_service (connection, name)) _dbus_wait_for_memory (); - scd.skip_connection = NULL; + scd.skip_connection = connection; /* we haven't done AddMatch so won't get it ourselves */ scd.failed = FALSE; scd.expected_service_name = name; bus_test_clients_foreach (check_service_created_foreach, @@ -857,6 +894,126 @@ check_hello_message (BusContext *context, return retval; } +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_add_match_all (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_bool_t retval; + dbus_uint32_t serial; + DBusError error; + + retval = FALSE; + dbus_error_init (&error); + message = NULL; + + _dbus_verbose ("check_add_match_all for %p\n", connection); + + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "AddMatch"); + + if (message == NULL) + return TRUE; + + if (!dbus_message_append_args (message, DBUS_TYPE_STRING, "", /* FIXME */ + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + /* send our message */ + bus_test_run_clients_loop (TRUE); + + dbus_connection_ref (connection); /* because we may get disconnected */ + block_connection_until_message_from_bus (context, connection); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected\n"); + + dbus_connection_unref (connection); + + return TRUE; + } + + dbus_connection_unref (connection); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "AddMatch", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + ; /* good, expected */ + _dbus_assert (dbus_message_get_reply_serial (message) == serial); + } + else + { + warn_unexpected (connection, message, "method return for AddMatch"); + + goto out; + } + } + + if (!check_no_leftovers (context)) + goto out; + + retval = TRUE; + + out: + dbus_error_free (&error); + + if (message) + dbus_message_unref (message); + + return retval; +} + /* returns TRUE if the correct thing happens, * but the correct thing may include OOM errors. */ @@ -885,7 +1042,7 @@ check_hello_connection (BusContext *context) if (!check_hello_message (context, connection)) return FALSE; - + if (dbus_bus_get_base_service (connection) == NULL) { /* We didn't successfully register, so we can't @@ -895,6 +1052,9 @@ check_hello_connection (BusContext *context) } else { + if (!check_add_match_all (context, connection)) + return FALSE; + kill_client_connection (context, connection); } @@ -911,7 +1071,7 @@ check_nonexistent_service_activation (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; @@ -1293,7 +1453,7 @@ check_send_exit_to_service (BusContext *context, { dbus_bool_t got_error; DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; _dbus_verbose ("Sending exit message to the test service\n"); @@ -1462,7 +1622,7 @@ check_existent_service_activation (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; char *base_service; @@ -1676,7 +1836,7 @@ check_segfault_service_activation (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; @@ -1877,6 +2037,9 @@ bus_dispatch_test (const DBusString *test_data_dir) if (!check_hello_message (context, foo)) _dbus_assert_not_reached ("hello message failed"); + + if (!check_add_match_all (context, foo)) + _dbus_assert_not_reached ("AddMatch message failed"); bar = dbus_connection_open ("debug-pipe:name=test-server", &error); if (bar == NULL) @@ -1887,6 +2050,9 @@ bus_dispatch_test (const DBusString *test_data_dir) if (!check_hello_message (context, bar)) _dbus_assert_not_reached ("hello message failed"); + + if (!check_add_match_all (context, bar)) + _dbus_assert_not_reached ("AddMatch message failed"); baz = dbus_connection_open ("debug-pipe:name=test-server", &error); if (baz == NULL) @@ -1898,6 +2064,9 @@ bus_dispatch_test (const DBusString *test_data_dir) if (!check_hello_message (context, baz)) _dbus_assert_not_reached ("hello message failed"); + if (!check_add_match_all (context, baz)) + _dbus_assert_not_reached ("AddMatch message failed"); + if (!check_no_leftovers (context)) { _dbus_warn ("Messages were left over after setting up initial connections"); @@ -1954,6 +2123,9 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir) if (!check_hello_message (context, foo)) _dbus_assert_not_reached ("hello message failed"); + if (!check_add_match_all (context, foo)) + _dbus_assert_not_reached ("addmatch message failed"); + if (!check_no_leftovers (context)) { _dbus_warn ("Messages were left over after setting up initial SHA-1 connection\n"); diff --git a/bus/dispatch.h b/bus/dispatch.h index 18f74529..d8107b1a 100644 --- a/bus/dispatch.h +++ b/bus/dispatch.h @@ -29,8 +29,9 @@ dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection); void bus_dispatch_remove_connection (DBusConnection *connection); -dbus_bool_t bus_dispatch_broadcast_message (BusTransaction *transaction, +dbus_bool_t bus_dispatch_matches (BusTransaction *transaction, DBusConnection *sender, + DBusConnection *recipient, DBusMessage *message, DBusError *error); diff --git a/bus/driver.c b/bus/driver.c index 61bfe1c5..791fcd69 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -27,6 +27,7 @@ #include "driver.h" #include "dispatch.h" #include "services.h" +#include "signals.h" #include "utils.h" #include #include @@ -69,7 +70,7 @@ bus_driver_send_service_deleted (const char *service_name, return FALSE; } - retval = bus_dispatch_broadcast_message (transaction, NULL, message, error); + retval = bus_dispatch_matches (transaction, NULL, NULL, message, error); dbus_message_unref (message); return retval; @@ -111,7 +112,7 @@ bus_driver_send_service_created (const char *service_name, return FALSE; } - retval = bus_dispatch_broadcast_message (transaction, NULL, message, error); + retval = bus_dispatch_matches (transaction, NULL, NULL, message, error); dbus_message_unref (message); return retval; @@ -331,6 +332,7 @@ bus_driver_handle_hello (DBusConnection *connection, bus_service_set_prohibit_replacement (service, TRUE); + _dbus_assert (bus_connection_is_active (connection)); retval = TRUE; out_0: @@ -600,6 +602,160 @@ bus_driver_handle_activate_service (DBusConnection *connection, return retval; } +static dbus_bool_t +send_ack_reply (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply; + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + { + BUS_SET_OOM (error); + dbus_message_unref (reply); + return FALSE; + } + + dbus_message_unref (reply); + + return TRUE; +} + +static dbus_bool_t +bus_driver_handle_add_match (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusMatchRule *rule; + char *text; + DBusString str; + BusMatchmaker *matchmaker; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + text = NULL; + rule = NULL; + + if (bus_connection_get_n_match_rules (connection) >= + bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction))) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "Connection \"%s\" is not allowed to add more match rules " + "(increase limits in configuration file if required)", + bus_connection_is_active (connection) ? + bus_connection_get_name (connection) : + "(inactive)"); + goto failed; + } + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + { + _dbus_verbose ("No memory to get arguments to AddMatch\n"); + goto failed; + } + + _dbus_string_init_const (&str, text); + + rule = bus_match_rule_parse (connection, &str, error); + if (rule == NULL) + goto failed; + + matchmaker = bus_connection_get_matchmaker (connection); + + if (!bus_matchmaker_add_rule (matchmaker, rule)) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!send_ack_reply (connection, transaction, + message, error)) + { + bus_matchmaker_remove_rule (matchmaker, rule); + goto failed; + } + + bus_match_rule_unref (rule); + dbus_free (text); + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (rule) + bus_match_rule_unref (rule); + if (text) + dbus_free (text); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_remove_match (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusMatchRule *rule; + char *text; + DBusString str; + BusMatchmaker *matchmaker; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + text = NULL; + rule = NULL; + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + { + _dbus_verbose ("No memory to get arguments to RemoveMatch\n"); + goto failed; + } + + _dbus_string_init_const (&str, text); + + rule = bus_match_rule_parse (connection, &str, error); + if (rule == NULL) + goto failed; + + /* Send the ack before we remove the rule, since the ack is undone + * on transaction cancel, but rule removal isn't. + */ + if (!send_ack_reply (connection, transaction, + message, error)) + goto failed; + + matchmaker = bus_connection_get_matchmaker (connection); + + if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error)) + goto failed; + + bus_match_rule_unref (rule); + dbus_free (text); + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (rule) + bus_match_rule_unref (rule); + if (text) + dbus_free (text); + return FALSE; +} + /* For speed it might be useful to sort this in order of * frequency of use (but doesn't matter with only a few items * anyhow) @@ -616,7 +772,9 @@ struct { "ActivateService", bus_driver_handle_activate_service }, { "Hello", bus_driver_handle_hello }, { "ServiceExists", bus_driver_handle_service_exists }, - { "ListServices", bus_driver_handle_list_services } + { "ListServices", bus_driver_handle_list_services }, + { "AddMatch", bus_driver_handle_add_match }, + { "RemoveMatch", bus_driver_handle_remove_match } }; dbus_bool_t diff --git a/bus/policy.c b/bus/policy.c index 21d0b02e..2d462fb6 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -917,16 +917,33 @@ dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy, BusRegistry *registry, DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, DBusMessage *message) { DBusList *link; dbus_bool_t allowed; + dbus_bool_t eavesdropping; + + /* NULL sender, proposed_recipient means the bus driver. NULL + * addressed_recipient means the message didn't specify an explicit + * target. If proposed_recipient is NULL, then addressed_recipient + * is also NULL but is implicitly the bus driver. + */ + + _dbus_assert (proposed_recipient == NULL || + (dbus_message_get_destination (message) == NULL || + addressed_recipient != NULL)); + + eavesdropping = + (proposed_recipient == NULL || /* explicitly to bus driver */ + (addressed_recipient && addressed_recipient != proposed_recipient)); /* explicitly to a different recipient */ /* policy->rules is in the order the rules appeared * in the config file, i.e. last rule that applies wins */ - _dbus_verbose (" (policy) checking receive rules\n"); + _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping); allowed = FALSE; link = _dbus_list_get_first_link (&policy->rules); @@ -950,6 +967,24 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, continue; } } + + /* for allow, eavesdrop=false means the rule doesn't apply when + * eavesdropping. eavesdrop=true means always allow. + */ + if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n"); + continue; + } + + /* for deny, eavesdrop=true means the rule applies only when + * eavesdropping; eavesdrop=false means always deny. + */ + if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n"); + continue; + } if (rule->d.receive.path != NULL) { @@ -1036,7 +1071,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, } } } - + /* Use this rule */ allowed = rule->allow; diff --git a/bus/policy.h b/bus/policy.h index 5824816c..63981cc0 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -74,6 +74,7 @@ struct BusPolicyRule char *member; char *error; char *origin; + unsigned int eavesdrop : 1; } receive; struct @@ -134,6 +135,8 @@ dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy, dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy, BusRegistry *registry, DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, DBusMessage *message); dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy, DBusConnection *connection, diff --git a/bus/session.conf.in b/bus/session.conf.in index 09dd250e..45945688 100644 --- a/bus/session.conf.in +++ b/bus/session.conf.in @@ -14,10 +14,9 @@ - - + - + - - + +