diff options
Diffstat (limited to 'bus')
-rw-r--r-- | bus/Makefile.am | 2 | ||||
-rw-r--r-- | bus/activation.c | 4 | ||||
-rw-r--r-- | bus/bus.c | 97 | ||||
-rw-r--r-- | bus/bus.h | 71 | ||||
-rw-r--r-- | bus/config-parser.c | 310 | ||||
-rw-r--r-- | bus/connection.c | 169 | ||||
-rw-r--r-- | bus/connection.h | 13 | ||||
-rw-r--r-- | bus/dbus-daemon-1.1.in | 90 | ||||
-rw-r--r-- | bus/desktop-file.c | 14 | ||||
-rw-r--r-- | bus/dispatch.c | 647 | ||||
-rw-r--r-- | bus/dispatch.h | 3 | ||||
-rw-r--r-- | bus/driver.c | 250 | ||||
-rw-r--r-- | bus/policy.c | 178 | ||||
-rw-r--r-- | bus/policy.h | 21 | ||||
-rw-r--r-- | bus/services.c | 8 | ||||
-rw-r--r-- | bus/session.conf.in | 11 | ||||
-rw-r--r-- | bus/signals.c | 778 | ||||
-rw-r--r-- | bus/signals.h | 83 | ||||
-rw-r--r-- | bus/system.conf.in | 8 | ||||
-rw-r--r-- | bus/test-main.c | 6 | ||||
-rw-r--r-- | bus/test.c | 61 | ||||
-rw-r--r-- | bus/test.h | 1 |
22 files changed, 2317 insertions, 508 deletions
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/activation.c b/bus/activation.c index a52fa4bc..91d3c116 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -586,7 +586,7 @@ bus_activation_service_created (BusActivation *activation, if (dbus_connection_get_is_connected (entry->connection)) { - message = dbus_message_new_reply (entry->activation_message); + message = dbus_message_new_method_return (entry->activation_message); if (!message) { BUS_SET_OOM (error); @@ -866,7 +866,7 @@ bus_activation_activate_service (BusActivation *activation, { _dbus_verbose ("Service \"%s\" is already active\n", service_name); - message = dbus_message_new_reply (activation_message); + message = dbus_message_new_method_return (activation_message); if (!message) { @@ -28,6 +28,7 @@ #include "utils.h" #include "policy.h" #include "config-parser.h" +#include "signals.h" #include <dbus/dbus-list.h> #include <dbus/dbus-hash.h> #include <dbus/dbus-internals.h> @@ -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,21 +905,23 @@ 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 && - dbus_message_has_name (message, DBUS_MESSAGE_HELLO)) + if (proposed_recipient == NULL && + dbus_message_is_method_call (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "Hello")) { _dbus_verbose ("security check allowing %s message\n", - DBUS_MESSAGE_HELLO); + "Hello"); return TRUE; } else { _dbus_verbose ("security check disallowing non-%s message\n", - DBUS_MESSAGE_HELLO); + "Hello"); dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Client tried to send a message other than %s without being registered", - DBUS_MESSAGE_HELLO); + "Hello"); return FALSE; } @@ -895,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) @@ -920,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); @@ -934,9 +972,14 @@ bus_context_check_security_policy (BusContext *context, "A security policy in place prevents this sender " "from sending this message to this recipient, " "see message bus configuration file (rejected message " - "had name \"%s\" destination \"%s\")", - dbus_message_get_name (message), - dest ? dest : DBUS_SERVICE_DBUS); + "had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); _dbus_verbose ("security policy disallowing message due to sender policy\n"); return FALSE; } @@ -944,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); @@ -951,22 +995,29 @@ bus_context_check_security_policy (BusContext *context, "A security policy in place prevents this recipient " "from receiving this message from this sender, " "see message bus configuration file (rejected message " - "had name \"%s\" destination \"%s\")", - dbus_message_get_name (message), - dest ? dest : DBUS_SERVICE_DBUS); + "had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); _dbus_verbose ("security policy disallowing message due to recipient policy\n"); return FALSE; } /* 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_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; } @@ -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 c42278e1..7b9b962d 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -88,9 +88,12 @@ typedef struct } Element; +/** + * Parser for bus configuration file. + */ struct BusConfigParser { - int refcount; + int refcount; /**< Reference count */ DBusString basedir; /**< Directory we resolve paths relative to */ @@ -331,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; @@ -808,6 +813,21 @@ start_busconfig_child (BusConfigParser *parser, } } +static int +message_type_from_string (const char *type_str) +{ + if (strcmp (type_str, "method_call") == 0) + return DBUS_MESSAGE_TYPE_METHOD_CALL; + if (strcmp (type_str, "method_return") == 0) + return DBUS_MESSAGE_TYPE_METHOD_RETURN; + else if (strcmp (type_str, "signal") == 0) + return DBUS_MESSAGE_TYPE_SIGNAL; + else if (strcmp (type_str, "error") == 0) + return DBUS_MESSAGE_TYPE_ERROR; + else + return DBUS_MESSAGE_TYPE_INVALID; +} + static dbus_bool_t append_rule_from_element (BusConfigParser *parser, const char *element_name, @@ -816,11 +836,20 @@ append_rule_from_element (BusConfigParser *parser, dbus_bool_t allow, DBusError *error) { - const char *send; - const char *receive; + const char *send_interface; + const char *send_member; + const char *send_error; + 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_sender; + const char *receive_path; + const char *receive_type; + const char *eavesdrop; const char *own; - const char *send_to; - const char *receive_from; const char *user; const char *group; BusPolicyRule *rule; @@ -829,57 +858,147 @@ append_rule_from_element (BusConfigParser *parser, attribute_names, attribute_values, error, - "send", &send, - "receive", &receive, + "send_interface", &send_interface, + "send_member", &send_member, + "send_error", &send_error, + "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_sender", &receive_sender, + "receive_path", &receive_path, + "receive_type", &receive_type, + "eavesdrop", &eavesdrop, "own", &own, - "send_to", &send_to, - "receive_from", &receive_from, "user", &user, "group", &group, NULL)) return FALSE; - if (!(send || receive || own || send_to || receive_from || - user || group)) + if (!(send_interface || send_member || send_error || send_destination || + send_type || send_path || + receive_interface || receive_member || receive_error || receive_sender || + receive_type || receive_path || eavesdrop || + own || user || group)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Element <%s> must have one or more attributes", element_name); return FALSE; } + + if ((send_member && (send_interface == NULL && send_path == NULL)) || + (receive_member && (receive_interface == NULL && receive_path == NULL))) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "On element <%s>, if you specify a member you must specify an interface or a path. Keep in mind that not all messages have an interface field.", + element_name); + return FALSE; + } - if (((send && own) || - (send && receive) || - (send && receive_from) || - (send && user) || - (send && group)) || - - ((receive && own) || - (receive && send_to) || - (receive && user) || - (receive && group)) || - - ((own && send_to) || - (own && receive_from) || - (own && user) || - (own && group)) || + /* Allowed combinations of elements are: + * + * base, must be all send or all receive: + * nothing + * interface + * interface + member + * error + * + * 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. + */ - ((send_to && receive_from) || - (send_to && user) || - (send_to && group)) || + if (((send_interface && send_error) || + (send_interface && receive_interface) || + (send_interface && receive_member) || + (send_interface && receive_error) || + (send_interface && receive_sender) || + (send_interface && eavesdrop) || + (send_interface && own) || + (send_interface && user) || + (send_interface && group)) || + + ((send_member && send_error) || + (send_member && receive_interface) || + (send_member && receive_member) || + (send_member && receive_error) || + (send_member && receive_sender) || + (send_member && eavesdrop) || + (send_member && own) || + (send_member && user) || + (send_member && group)) || + + ((send_error && receive_interface) || + (send_error && receive_member) || + (send_error && receive_error) || + (send_error && receive_sender) || + (send_error && eavesdrop) || + (send_error && own) || + (send_error && user) || + (send_error && 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_sender) || + (send_type && eavesdrop) || + (send_type && own) || + (send_type && user) || + (send_type && group)) || + + ((send_path && receive_interface) || + (send_path && receive_member) || + (send_path && receive_error) || + (send_path && receive_sender) || + (send_path && eavesdrop) || + (send_path && own) || + (send_path && user) || + (send_path && group)) || + + ((receive_interface && receive_error) || + (receive_interface && own) || + (receive_interface && user) || + (receive_interface && group)) || + + ((receive_member && receive_error) || + (receive_member && own) || + (receive_member && user) || + (receive_member && group)) || + + ((receive_error && own) || + (receive_error && user) || + (receive_error && group)) || - ((receive_from && user) || - (receive_from && group)) || + ((eavesdrop && own) || + (eavesdrop && user) || + (eavesdrop && group)) || + + ((own && user) || + (own && group)) || - (user && group)) + ((user && group))) { dbus_set_error (error, DBUS_ERROR_FAILED, - "Invalid combination of attributes on element <%s>, " - "only send/send_to or receive/receive_from may be paired", + "Invalid combination of attributes on element <%s>", element_name); return FALSE; } - + rule = NULL; /* In BusPolicyRule, NULL represents wildcard. @@ -887,41 +1006,122 @@ append_rule_from_element (BusConfigParser *parser, */ #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0') - if (send || send_to) + if (send_interface || send_member || send_error || send_destination || + send_path || send_type) { + int message_type; + + if (IS_WILDCARD (send_interface)) + send_interface = NULL; + if (IS_WILDCARD (send_member)) + send_member = NULL; + if (IS_WILDCARD (send_error)) + send_error = NULL; + if (IS_WILDCARD (send_destination)) + send_destination = NULL; + if (IS_WILDCARD (send_path)) + send_path = NULL; + if (IS_WILDCARD (send_type)) + send_type = NULL; + + message_type = DBUS_MESSAGE_TYPE_INVALID; + if (send_type != NULL) + { + message_type = message_type_from_string (send_type); + if (message_type == DBUS_MESSAGE_TYPE_INVALID) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad message type \"%s\"", + send_type); + return FALSE; + } + } + rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); if (rule == NULL) goto nomem; - - if (IS_WILDCARD (send)) - send = NULL; - if (IS_WILDCARD (send_to)) - send_to = NULL; - rule->d.send.message_name = _dbus_strdup (send); - rule->d.send.destination = _dbus_strdup (send_to); - if (send && rule->d.send.message_name == NULL) + 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_destination); + if (send_path && rule->d.send.path == NULL) + goto nomem; + if (send_interface && rule->d.send.interface == NULL) + goto nomem; + if (send_member && rule->d.send.member == NULL) + goto nomem; + if (send_error && rule->d.send.error == NULL) goto nomem; - if (send_to && rule->d.send.destination == NULL) + if (send_destination && rule->d.send.destination == NULL) goto nomem; } - else if (receive || receive_from) + else if (receive_interface || receive_member || receive_error || receive_sender || + receive_path || receive_type || eavesdrop) { + int message_type; + + if (IS_WILDCARD (receive_interface)) + receive_interface = NULL; + if (IS_WILDCARD (receive_member)) + receive_member = NULL; + if (IS_WILDCARD (receive_error)) + receive_error = 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) + { + message_type = message_type_from_string (receive_type); + if (message_type == DBUS_MESSAGE_TYPE_INVALID) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad message type \"%s\"", + receive_type); + 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 (IS_WILDCARD (receive)) - receive = NULL; - - if (IS_WILDCARD (receive_from)) - receive_from = NULL; + if (eavesdrop) + rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0); - rule->d.receive.message_name = _dbus_strdup (receive); - rule->d.receive.origin = _dbus_strdup (receive_from); - if (receive && rule->d.receive.message_name == NULL) + 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_sender); + if (receive_path && rule->d.receive.path == NULL) + goto nomem; + if (receive_interface && rule->d.receive.interface == NULL) + goto nomem; + if (receive_member && rule->d.receive.member == NULL) + goto nomem; + if (receive_error && rule->d.receive.error == NULL) goto nomem; - if (receive_from && 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 5121658d..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 <dbus/dbus-list.h> #include <dbus/dbus-hash.h> #include <dbus/dbus-timeout.h> @@ -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. * @@ -963,19 +1022,19 @@ bus_connection_preallocate_oom_error (DBusConnection *connection) if (preallocated == NULL) return FALSE; - /* d->name may be NULL, but that is OK */ - message = dbus_message_new (DBUS_ERROR_NO_MEMORY, - d->name); + message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); + if (message == NULL) { dbus_connection_free_preallocated_send (connection, preallocated); return FALSE; } - dbus_message_set_is_error (message, TRUE); - - if (!dbus_message_set_sender (message, - DBUS_SERVICE_DBUS)) + /* d->name may be NULL, but that is OK */ + if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) || + !dbus_message_set_destination (message, d->name) || + !dbus_message_set_sender (message, + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { dbus_connection_free_preallocated_send (connection, preallocated); dbus_message_unref (message); @@ -1025,6 +1084,62 @@ bus_connection_send_oom_error (DBusConnection *connection, } 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; } @@ -1312,17 +1431,22 @@ bus_transaction_send_from_driver (BusTransaction *transaction, * to check security policy since it was not done in * dispatch.c */ - _dbus_verbose ("Sending %s from driver\n", - dbus_message_get_name (message)); - - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + _dbus_verbose ("Sending %s %s %s from driver\n", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(no interface)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(no member)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(no error name)"); + + if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) return FALSE; /* If security policy doesn't allow the message, we silently * 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); @@ -1337,11 +1461,16 @@ bus_transaction_send (BusTransaction *transaction, BusConnectionData *d; DBusList *link; - _dbus_verbose (" trying to add %s %s to transaction%s\n", - dbus_message_get_is_error (message) ? "error" : + _dbus_verbose (" trying to add %s interface=%s member=%s error=%s to transaction%s\n", + dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" : dbus_message_get_reply_serial (message) != 0 ? "reply" : "message", - dbus_message_get_name (message), + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", dbus_connection_get_is_connected (connection) ? "" : " (disconnected)"); @@ -1550,13 +1679,13 @@ bus_transaction_send_error_reply (BusTransaction *transaction, _dbus_assert (error != NULL); _DBUS_ASSERT_ERROR_IS_SET (error); - + _dbus_verbose ("Sending error reply %s \"%s\"\n", error->name, error->message); - reply = dbus_message_new_error_reply (in_reply_to, - error->name, - error->message); + reply = dbus_message_new_error (in_reply_to, + error->name, + error->message); if (reply == NULL) return FALSE; 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 73a88c90..b272a62e 100644 --- a/bus/dbus-daemon-1.1.in +++ b/bus/dbus-daemon-1.1.in @@ -328,16 +328,33 @@ in the config file. .TP .I "<deny>" +.I "<allow>" + +.PP +A <deny> element appears below a <policy> element and prohibits some +action. The <allow> element makes an exception to previous <deny> +statements, and works just like <deny> but with the inverse meaning. .PP -A <deny> element appears below a <policy> element and prohibits -some action. The possible attributes of a <deny> element are: +The possible attributes of these elements are: .nf - send="messagename" - receive="messagename" + send_interface="interface_name" + send_member="method_or_signal_name" + send_error="error_name" + 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_sender="service_name" + receive_type="method_call" | "method_return" | "signal" | "error" + receive_path="/path/name" + + eavesdrop="true" | "false" + own="servicename" - send_to="servicename" - receive_from="servicename" user="username" group="groupname" .fi @@ -345,11 +362,11 @@ some action. The possible attributes of a <deny> element are: .PP Examples: .nf - <deny send="org.freedesktop.System.Reboot"/> - <deny receive="org.freedesktop.System.Reboot"/> + <deny send_interface="org.freedesktop.System" send_member="Reboot"/> + <deny receive_interface="org.freedesktop.System" receive_member="Reboot"/> <deny own="org.freedesktop.System"/> - <deny send_to="org.freedesktop.System"/> - <deny receive_from="org.freedesktop.System"/> + <deny send_destination="org.freedesktop.System"/> + <deny receive_sender="org.freedesktop.System"/> <deny user="john"/> <deny group="enemies"/> .fi @@ -360,18 +377,38 @@ particular action. If it matches, the action is denied (unless later rules in the config file allow it). .PP -send_to and receive_from 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 will not work -either. +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 +will not work either. + +.PP +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 <allow>, 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 <deny>, eavesdrop="true" indicates that the rule matches +only when eavesdropping. eavesdrop="false" is the default for <deny> +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. .PP -For "servicename" or "messagename" or "username" or "groupname" +For "service_name", "username", "groupname", etc. the character "*" can be substituted, meaning "any." Complex globs like "foo.bar.*" aren't allowed for now because they'd be work to implement and maybe encourage sloppy security anyway. @@ -382,18 +419,21 @@ for a user or group; user/group denials can only be inside context="default" or context="mandatory" policies. .PP -A single <deny> rule may specify both send and send_to, OR both -receive and receive_from. In this case, the denial applies only if -both attributes match the message being denied. -e.g. <deny send="foo.bar" send_to="foo.blah"/> would deny -messages of the given name AND to the given service. +A single <deny> rule may specify combinations of attributes such as +send_service and send_interface and send_type. In this case, the +denial applies only if both attributes match the message being denied. +e.g. <deny send_interface="foo.bar" send_service="foo.blah"/> would +deny messages of the given interface AND to the given service. +To get an OR effect you specify multiple <deny> rules. -.TP -.I "<allow>" +.PP +You can't include both send_ and receive_ attributes on the same +rule, since "whether the message can be sent" and "whether it can be +received" are evaluated separately. .PP -Makes an exception to previous <deny> statements. Works -just like <deny> but with the inverse meaning. +Be careful with send_interface/receive_interface, because the +interface field in messages is optional. .SH AUTHOR See http://www.freedesktop.org/software/dbus/doc/AUTHORS diff --git a/bus/desktop-file.c b/bus/desktop-file.c index 08af768e..dd621214 100644 --- a/bus/desktop-file.c +++ b/bus/desktop-file.c @@ -48,15 +48,19 @@ struct BusDesktopFile int n_allocated_sections; }; +/** + * Parser for service files. + */ typedef struct { - DBusString data; + DBusString data; /**< The data from the file */ - BusDesktopFile *desktop_file; - int current_section; + BusDesktopFile *desktop_file; /**< The resulting object */ + int current_section; /**< The current section being parsed */ - int pos, len; - int line_num; + int pos; /**< Current position */ + int len; /**< Length */ + int line_num; /**< Current line number */ } BusDesktopFileParser; diff --git a/bus/dispatch.c b/bus/dispatch.c index d43e8121..606c68ef 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -28,38 +28,33 @@ #include "services.h" #include "utils.h" #include "bus.h" +#include "signals.h" #include "test.h" #include <dbus/dbus-internals.h> #include <string.h> -static dbus_int32_t message_handler_slot = -1; - -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; } @@ -67,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); @@ -100,16 +125,21 @@ bus_dispatch_broadcast_message (BusTransaction *transaction, return TRUE; } -static void +static DBusHandlerResult bus_dispatch (DBusConnection *connection, DBusMessage *message) { - const char *sender, *service_name, *message_name; + const char *sender, *service_name; DBusError error; 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); @@ -123,32 +153,50 @@ bus_dispatch (DBusConnection *connection, /* Ref connection in case we disconnect it at some point in here */ dbus_connection_ref (connection); - + service_name = dbus_message_get_destination (message); - message_name = dbus_message_get_name (message); - - _dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */ - _dbus_verbose ("DISPATCH: %s to %s\n", - message_name, service_name ? service_name : "peer"); - - /* 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 +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + const char *interface_name, *member_name, *error_name; + + interface_name = dbus_message_get_interface (message); + member_name = dbus_message_get_member (message); + error_name = dbus_message_get_error_name (message); + + _dbus_verbose ("DISPATCH: %s %s %s to %s\n", + interface_name ? interface_name : "(no interface)", + member_name ? member_name : "(no member)", + error_name ? error_name : "(no error name)", + service_name ? service_name : "peer"); + } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + + /* 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 (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0) - bus_connection_disconnected (connection); + { + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) + { + bus_connection_disconnected (connection); + goto out; + } - /* DBusConnection also handles some of these automatically, we leave - * it to do so. - */ - 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); @@ -177,17 +225,18 @@ bus_dispatch (DBusConnection *connection, */ service_name = dbus_message_get_destination (message); } - - if (strcmp (service_name, DBUS_SERVICE_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; } - _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS); + _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (!bus_driver_handle_message (connection, transaction, message, &error)) goto out; } @@ -195,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_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); @@ -225,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)) @@ -295,66 +344,26 @@ bus_dispatch (DBusConnection *connection, } dbus_connection_unref (connection); -} -static DBusHandlerResult -bus_dispatch_message_handler (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message, - void *user_data) -{ - bus_dispatch (connection, message); - - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return result; } -static void -free_message_handler (void *data) +static DBusHandlerResult +bus_dispatch_message_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) { - DBusMessageHandler *handler = data; - - _dbus_assert (message_handler_slot >= 0); - - dbus_message_handler_unref (handler); - dbus_connection_free_data_slot (&message_handler_slot); + return bus_dispatch (connection, message); } dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection) -{ - DBusMessageHandler *handler; - - if (!dbus_connection_allocate_data_slot (&message_handler_slot)) +{ + if (!dbus_connection_add_filter (connection, + bus_dispatch_message_filter, + NULL, NULL)) return FALSE; - handler = dbus_message_handler_new (bus_dispatch_message_handler, NULL, NULL); - if (handler == NULL) - { - dbus_connection_free_data_slot (&message_handler_slot); - return FALSE; - } - - if (!dbus_connection_add_filter (connection, handler)) - { - dbus_message_handler_unref (handler); - dbus_connection_free_data_slot (&message_handler_slot); - - return FALSE; - } - - _dbus_assert (message_handler_slot >= 0); - - if (!dbus_connection_set_data (connection, - message_handler_slot, - handler, - free_message_handler)) - { - dbus_message_handler_unref (handler); - dbus_connection_free_data_slot (&message_handler_slot); - - return FALSE; - } - return TRUE; } @@ -364,9 +373,9 @@ bus_dispatch_remove_connection (DBusConnection *connection) /* Here we tell the bus driver that we want to get off. */ bus_driver_remove_connection (connection); - dbus_connection_set_data (connection, - message_handler_slot, - NULL, NULL); + dbus_connection_remove_filter (connection, + bus_dispatch_message_filter, + NULL); } #ifdef DBUS_BUILD_TESTS @@ -401,6 +410,42 @@ pop_message_waiting_for_memory (DBusConnection *connection) return dbus_connection_pop_message (connection); } +static void +warn_unexpected_real (DBusConnection *connection, + DBusMessage *message, + const char *expected, + const char *function, + int line) +{ + _dbus_warn ("%s:%d received message interface \"%s\" member \"%s\" error name \"%s\" on %p, expecting %s\n", + function, line, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + connection, + expected); +} + +#define warn_unexpected(connection, message, expected) \ + warn_unexpected_real (connection, message, expected, _DBUS_FUNCTION_NAME, __LINE__) + +static void +verbose_message_received (DBusConnection *connection, + DBusMessage *message) +{ + _dbus_verbose ("Received message interface \"%s\" member \"%s\" error name \"%s\" on %p\n", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + connection); +} + typedef struct { const char *expected_service_name; @@ -424,14 +469,15 @@ check_service_deleted_foreach (DBusConnection *connection, if (message == NULL) { _dbus_warn ("Did not receive a message on %p, expecting %s\n", - connection, DBUS_MESSAGE_SERVICE_DELETED); + connection, "ServiceDeleted"); goto out; } - else if (!dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_DELETED)) + else if (!dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceDeleted")) { - _dbus_warn ("Received message %s on %p, expecting %s\n", - dbus_message_get_name (message), - connection, DBUS_MESSAGE_SERVICE_DELETED); + warn_unexpected (connection, message, "ServiceDeleted"); + goto out; } else @@ -554,8 +600,8 @@ check_no_messages_foreach (DBusConnection *connection, message = pop_message_waiting_for_memory (connection); if (message != NULL) { - _dbus_warn ("Received message %s on %p, expecting no messages\n", - dbus_message_get_name (message), connection); + warn_unexpected (connection, message, "no messages"); + d->failed = TRUE; } @@ -591,14 +637,14 @@ check_service_created_foreach (DBusConnection *connection, if (message == NULL) { _dbus_warn ("Did not receive a message on %p, expecting %s\n", - connection, DBUS_MESSAGE_SERVICE_CREATED); + connection, "ServiceCreated"); goto out; } - else if (!dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED)) + else if (!dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceCreated")) { - _dbus_warn ("Received message %s on %p, expecting %s\n", - dbus_message_get_name (message), - connection, DBUS_MESSAGE_SERVICE_CREATED); + warn_unexpected (connection, message, "ServiceCreated"); goto out; } else @@ -662,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; @@ -673,9 +719,13 @@ check_hello_message (BusContext *context, name = NULL; acquired = NULL; message = NULL; + + _dbus_verbose ("check_hello_message for %p\n", connection); - message = dbus_message_new (DBUS_MESSAGE_HELLO, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "Hello"); if (message == NULL) return TRUE; @@ -710,14 +760,13 @@ check_hello_message (BusContext *context, if (message == NULL) { _dbus_warn ("Did not receive a reply to %s %d on %p\n", - DBUS_MESSAGE_HELLO, serial, connection); + "Hello", serial, connection); goto out; } - _dbus_verbose ("Received %s on %p\n", - dbus_message_get_name (message), connection); + verbose_message_received (connection, message); - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -725,17 +774,17 @@ check_hello_message (BusContext *context, goto out; } - if (dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (dbus_message_has_name (message, + if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } else { - _dbus_warn ("Did not expect error %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "not this error"); + goto out; } } @@ -743,15 +792,14 @@ check_hello_message (BusContext *context, { CheckServiceCreatedData scd; - if (dbus_message_has_name (message, - DBUS_MESSAGE_HELLO)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) { ; /* good, expected */ } else { - _dbus_warn ("Did not expect reply %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "method return for Hello"); + goto out; } @@ -780,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, @@ -795,7 +843,7 @@ check_hello_message (BusContext *context, if (message == NULL) { _dbus_warn ("Expecting %s, got nothing\n", - DBUS_MESSAGE_SERVICE_ACQUIRED); + "ServiceAcquired"); goto out; } @@ -850,6 +898,126 @@ check_hello_message (BusContext *context, * 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. + */ +static dbus_bool_t check_hello_connection (BusContext *context) { DBusConnection *connection; @@ -874,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 @@ -884,6 +1052,9 @@ check_hello_connection (BusContext *context) } else { + if (!check_add_match_all (context, connection)) + return FALSE; + kill_client_connection (context, connection); } @@ -900,14 +1071,16 @@ check_nonexistent_service_activation (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; dbus_error_init (&error); - message = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService"); if (message == NULL) return TRUE; @@ -946,16 +1119,15 @@ check_nonexistent_service_activation (BusContext *context, if (message == NULL) { _dbus_warn ("Did not receive a reply to %s %d on %p\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection); + "ActivateService", serial, connection); goto out; } - _dbus_verbose ("Received %s on %p\n", - dbus_message_get_name (message), connection); + verbose_message_received (connection, message); - if (dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -963,20 +1135,19 @@ check_nonexistent_service_activation (BusContext *context, goto out; } - if (dbus_message_has_name (message, + if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } - else if (dbus_message_has_name (message, + else if (dbus_message_is_error (message, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND)) { ; /* good, this is expected also */ } else { - _dbus_warn ("Did not expect error %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "not this error"); goto out; } } @@ -1015,7 +1186,9 @@ check_base_service_activated (BusContext *context, message = initial_message; dbus_message_ref (message); - if (dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED)) + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceCreated")) { char *service_name; CheckServiceCreatedData scd; @@ -1034,7 +1207,7 @@ check_base_service_activated (BusContext *context, else { _dbus_warn ("Message %s doesn't have a service name: %s\n", - dbus_message_get_name (message), + "ServiceCreated", error.message); dbus_error_free (&error); goto out; @@ -1062,8 +1235,8 @@ check_base_service_activated (BusContext *context, } else { - _dbus_warn ("Expected to get base service ServiceCreated, instead got %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "ServiceCreated for base service"); + goto out; } @@ -1104,7 +1277,9 @@ check_service_activated (BusContext *context, message = initial_message; dbus_message_ref (message); - if (dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED)) + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceCreated")) { char *service_name; CheckServiceCreatedData scd; @@ -1123,7 +1298,7 @@ check_service_activated (BusContext *context, else { _dbus_warn ("Message %s doesn't have a service name: %s\n", - dbus_message_get_name (message), + "ServiceCreated", error.message); dbus_error_free (&error); goto out; @@ -1154,22 +1329,21 @@ check_service_activated (BusContext *context, if (message == NULL) { _dbus_warn ("Expected a reply to %s, got nothing\n", - DBUS_MESSAGE_ACTIVATE_SERVICE); + "ActivateService"); goto out; } } else { - _dbus_warn ("Expected to get service %s ServiceCreated, instead got %s\n", - activated_name, dbus_message_get_name (message)); + warn_unexpected (connection, message, "ServiceCreated for the activated name"); + goto out; } - if (!dbus_message_has_name (message, DBUS_MESSAGE_ACTIVATE_SERVICE)) + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) { - _dbus_warn ("Expected reply to %s, got message %s instead\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, - dbus_message_get_name (message)); + warn_unexpected (connection, message, "reply to ActivateService"); + goto out; } @@ -1181,7 +1355,7 @@ check_service_activated (BusContext *context, if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { _dbus_warn ("Did not have activation result first argument to %s: %s\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, error.message); + "ActivateService", error.message); dbus_error_free (&error); goto out; } @@ -1279,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"); @@ -1287,8 +1461,10 @@ check_send_exit_to_service (BusContext *context, retval = FALSE; /* Kill off the test service by sending it a quit message */ - message = dbus_message_new ("org.freedesktop.DBus.TestSuiteExit", - service_name); + message = dbus_message_new_method_call (service_name, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Exit"); if (message == NULL) { @@ -1324,7 +1500,7 @@ check_send_exit_to_service (BusContext *context, /* see if we got an error during message bus dispatching */ bus_test_run_clients_loop (FALSE); message = dbus_connection_borrow_message (connection); - got_error = message != NULL && dbus_message_get_is_error (message); + got_error = message != NULL && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR; if (message) { dbus_connection_return_message (connection, message); @@ -1344,21 +1520,16 @@ check_send_exit_to_service (BusContext *context, message = pop_message_waiting_for_memory (connection); _dbus_assert (message != NULL); - if (!dbus_message_get_is_error (message)) + if (!dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) { - _dbus_warn ("expecting an error reply to asking test service to exit, got %s\n", - dbus_message_get_name (message)); - goto out; - } - else if (!dbus_message_has_name (message, DBUS_ERROR_NO_MEMORY)) - { - _dbus_warn ("not expecting error %s when asking test service to exit\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, + "a no memory error from asking test service to exit"); goto out; } _dbus_verbose ("Got error %s when asking test service to exit\n", - dbus_message_get_name (message)); + dbus_message_get_error_name (message)); /* Do this again; we still need the service to exit... */ if (!check_send_exit_to_service (context, connection, @@ -1402,10 +1573,10 @@ check_got_error (BusContext *context, goto out; } - if (!dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) { - _dbus_warn ("Expected an error, got %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "an error"); + goto out; } @@ -1415,7 +1586,7 @@ check_got_error (BusContext *context, error_name = first_error_name; while (error_name != NULL) { - if (dbus_message_has_name (message, error_name)) + if (dbus_message_is_error (message, error_name)) { error_found = TRUE; break; @@ -1428,7 +1599,7 @@ check_got_error (BusContext *context, { _dbus_warn ("Expected error %s or other, got %s instead\n", first_error_name, - dbus_message_get_name (message)); + dbus_message_get_error_name (message)); goto out; } @@ -1451,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; @@ -1460,8 +1631,10 @@ check_existent_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService"); if (message == NULL) return TRUE; @@ -1505,17 +1678,16 @@ check_existent_service_activation (BusContext *context, if (message == NULL) { _dbus_warn ("Did not receive any messages after %s %d on %p\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection); + "ActivateService", serial, connection); goto out; } - _dbus_verbose ("Received %s on %p after sending %s\n", - dbus_message_get_name (message), connection, - DBUS_MESSAGE_ACTIVATE_SERVICE); + verbose_message_received (connection, message); + _dbus_verbose (" (after sending %s)\n", "ActivateService"); - if (dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -1523,12 +1695,12 @@ check_existent_service_activation (BusContext *context, goto out; } - if (dbus_message_has_name (message, + if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } - else if (dbus_message_has_name (message, + else if (dbus_message_is_error (message, DBUS_ERROR_SPAWN_CHILD_EXITED)) { ; /* good, this is expected also */ @@ -1536,7 +1708,7 @@ check_existent_service_activation (BusContext *context, else { _dbus_warn ("Did not expect error %s\n", - dbus_message_get_name (message)); + dbus_message_get_error_name (message)); goto out; } } @@ -1562,8 +1734,10 @@ check_existent_service_activation (BusContext *context, goto out; } - got_service_deleted = dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_DELETED); - got_error = dbus_message_get_is_error (message); + got_service_deleted = dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceDeleted"); + got_error = dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR; dbus_connection_return_message (connection, message); message = NULL; @@ -1662,14 +1836,16 @@ check_segfault_service_activation (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; dbus_error_init (&error); - message = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService"); if (message == NULL) return TRUE; @@ -1709,16 +1885,15 @@ check_segfault_service_activation (BusContext *context, if (message == NULL) { _dbus_warn ("Did not receive a reply to %s %d on %p\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection); + "ActivateService", serial, connection); goto out; } - _dbus_verbose ("Received %s on %p\n", - dbus_message_get_name (message), connection); + verbose_message_received (connection, message); - if (dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -1726,20 +1901,20 @@ check_segfault_service_activation (BusContext *context, goto out; } - if (dbus_message_has_name (message, - DBUS_ERROR_NO_MEMORY)) + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } - else if (dbus_message_has_name (message, - DBUS_ERROR_SPAWN_CHILD_SIGNALED)) + else if (dbus_message_is_error (message, + DBUS_ERROR_SPAWN_CHILD_SIGNALED)) { ; /* good, this is expected also */ } else { - _dbus_warn ("Did not expect error %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "not this error"); + goto out; } } @@ -1862,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) @@ -1872,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) @@ -1883,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"); @@ -1939,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 e0afd8ef..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 <dbus/dbus-string.h> #include <dbus/dbus-internals.h> @@ -49,15 +50,17 @@ bus_driver_send_service_deleted (const char *service_name, _dbus_verbose ("sending service deleted: %s\n", service_name); - message = dbus_message_new (DBUS_MESSAGE_SERVICE_DELETED, - DBUS_SERVICE_BROADCAST); + message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceDeleted"); + if (message == NULL) { BUS_SET_OOM (error); return FALSE; } - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) || + if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) || !dbus_message_append_args (message, DBUS_TYPE_STRING, service_name, DBUS_TYPE_INVALID)) @@ -67,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; @@ -83,15 +86,17 @@ bus_driver_send_service_created (const char *service_name, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new (DBUS_MESSAGE_SERVICE_CREATED, - DBUS_SERVICE_BROADCAST); + message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceCreated"); + if (message == NULL) { BUS_SET_OOM (error); return FALSE; } - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { dbus_message_unref (message); BUS_SET_OOM (error); @@ -107,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; @@ -123,15 +128,18 @@ bus_driver_send_service_lost (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new (DBUS_MESSAGE_SERVICE_LOST, - bus_connection_get_name (connection)); + message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceLost"); + if (message == NULL) { BUS_SET_OOM (error); return FALSE; } - if (!dbus_message_append_args (message, + if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) || + !dbus_message_append_args (message, DBUS_TYPE_STRING, service_name, DBUS_TYPE_INVALID)) { @@ -163,8 +171,9 @@ bus_driver_send_service_acquired (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new (DBUS_MESSAGE_SERVICE_ACQUIRED, - bus_connection_get_name (connection)); + message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceAcquired"); if (message == NULL) { @@ -172,7 +181,8 @@ bus_driver_send_service_acquired (DBusConnection *connection, return FALSE; } - if (!dbus_message_append_args (message, + if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) || + !dbus_message_append_args (message, DBUS_TYPE_STRING, service_name, DBUS_TYPE_INVALID)) { @@ -322,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: @@ -343,7 +354,7 @@ bus_driver_send_welcome_message (DBusConnection *connection, name = bus_connection_get_name (connection); _dbus_assert (name != NULL); - welcome = dbus_message_new_reply (hello_message); + welcome = dbus_message_new_method_return (hello_message); if (welcome == NULL) { BUS_SET_OOM (error); @@ -387,7 +398,7 @@ bus_driver_handle_list_services (DBusConnection *connection, registry = bus_connection_get_registry (connection); - reply = dbus_message_new_reply (message); + reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); @@ -463,7 +474,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection, error)) goto out; - reply = dbus_message_new_reply (message); + reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); @@ -518,7 +529,7 @@ bus_driver_handle_service_exists (DBusConnection *connection, _dbus_string_init_const (&service_name, name); service = bus_registry_lookup (registry, &service_name); - reply = dbus_message_new_reply (message); + reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); @@ -591,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) @@ -603,11 +768,13 @@ struct DBusMessage *message, DBusError *error); } message_handlers[] = { - { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service }, - { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service }, - { DBUS_MESSAGE_HELLO, bus_driver_handle_hello }, - { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists }, - { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services } + { "AcquireService", bus_driver_handle_acquire_service }, + { "ActivateService", bus_driver_handle_activate_service }, + { "Hello", bus_driver_handle_hello }, + { "ServiceExists", bus_driver_handle_service_exists }, + { "ListServices", bus_driver_handle_list_services }, + { "AddMatch", bus_driver_handle_add_match }, + { "RemoveMatch", bus_driver_handle_remove_match } }; dbus_bool_t @@ -620,15 +787,32 @@ bus_driver_handle_message (DBusConnection *connection, int i; _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) + { + _dbus_verbose ("Driver got a non-method-call message, ignoring\n"); + return TRUE; /* we just ignore this */ + } + + _dbus_assert (dbus_message_get_interface (message) != NULL); + _dbus_assert (dbus_message_get_member (message) != NULL); + + name = dbus_message_get_member (message); + sender = dbus_message_get_sender (message); - _dbus_verbose ("Driver got a message: %s\n", - dbus_message_get_name (message)); + if (strcmp (dbus_message_get_interface (message), + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS) != 0) + { + _dbus_verbose ("Driver got message to unknown interface \"%s\"\n", + dbus_message_get_interface (message)); + goto unknown; + } + + _dbus_verbose ("Driver got a method call: %s\n", + dbus_message_get_member (message)); - name = dbus_message_get_name (message); - sender = dbus_message_get_sender (message); - /* security checks should have kept this from getting here */ - _dbus_assert (sender != NULL || strcmp (name, DBUS_MESSAGE_HELLO) == 0); + _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0); if (dbus_message_get_reply_serial (message) == 0) { @@ -659,11 +843,13 @@ bus_driver_handle_message (DBusConnection *connection, ++i; } - _dbus_verbose ("No driver handler for %s\n", name); + unknown: + _dbus_verbose ("No driver handler for message \"%s\"\n", + name); - dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE, + dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD, "%s does not understand message %s", - DBUS_SERVICE_DBUS, name); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, name); return FALSE; } diff --git a/bus/policy.c b/bus/policy.c index 2f8e2ca3..2d462fb6 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -52,7 +52,11 @@ bus_policy_rule_new (BusPolicyRuleType type, rule->d.group.gid = DBUS_GID_UNSET; break; case BUS_POLICY_RULE_SEND: + rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID; + break; case BUS_POLICY_RULE_RECEIVE: + rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID; + break; case BUS_POLICY_RULE_OWN: break; } @@ -80,11 +84,17 @@ bus_policy_rule_unref (BusPolicyRule *rule) switch (rule->type) { case BUS_POLICY_RULE_SEND: - dbus_free (rule->d.send.message_name); + dbus_free (rule->d.send.path); + dbus_free (rule->d.send.interface); + dbus_free (rule->d.send.member); + dbus_free (rule->d.send.error); dbus_free (rule->d.send.destination); break; case BUS_POLICY_RULE_RECEIVE: - dbus_free (rule->d.receive.message_name); + dbus_free (rule->d.receive.path); + dbus_free (rule->d.receive.interface); + dbus_free (rule->d.receive.member); + dbus_free (rule->d.receive.error); dbus_free (rule->d.receive.origin); break; case BUS_POLICY_RULE_OWN: @@ -680,8 +690,8 @@ bus_client_policy_optimize (BusClientPolicy *policy) /* The idea here is that if we have: * - * <allow send="foo"/> - * <deny send="*"/> + * <allow send_interface="foo.bar"/> + * <deny send_interface="*"/> * * (for example) the deny will always override the allow. So we * delete the allow. Ditto for deny followed by allow, etc. This is @@ -713,12 +723,20 @@ bus_client_policy_optimize (BusClientPolicy *policy) { case BUS_POLICY_RULE_SEND: remove_preceding = - rule->d.send.message_name == NULL && + rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID && + rule->d.send.path == NULL && + rule->d.send.interface == NULL && + rule->d.send.member == NULL && + rule->d.send.error == NULL && rule->d.send.destination == NULL; break; case BUS_POLICY_RULE_RECEIVE: remove_preceding = - rule->d.receive.message_name == NULL && + rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID && + rule->d.receive.path == NULL && + rule->d.receive.interface == NULL && + rule->d.receive.member == NULL && + rule->d.receive.error == NULL && rule->d.receive.origin == NULL; break; case BUS_POLICY_RULE_OWN: @@ -791,16 +809,59 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, continue; } - if (rule->d.send.message_name != NULL) + if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID) + { + if (dbus_message_get_type (message) != rule->d.send.message_type) + { + _dbus_verbose (" (policy) skipping rule for different message type\n"); + continue; + } + } + + if (rule->d.send.path != NULL) + { + if (dbus_message_get_path (message) != NULL && + strcmp (dbus_message_get_path (message), + rule->d.send.path) != 0) + { + _dbus_verbose (" (policy) skipping rule for different path\n"); + continue; + } + } + + if (rule->d.send.interface != NULL) { - if (!dbus_message_has_name (message, - rule->d.send.message_name)) + if (dbus_message_get_interface (message) != NULL && + strcmp (dbus_message_get_interface (message), + rule->d.send.interface) != 0) { - _dbus_verbose (" (policy) skipping rule for different message name\n"); + _dbus_verbose (" (policy) skipping rule for different interface\n"); continue; } } + if (rule->d.send.member != NULL) + { + if (dbus_message_get_member (message) != NULL && + strcmp (dbus_message_get_member (message), + rule->d.send.member) != 0) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + continue; + } + } + + if (rule->d.send.error != NULL) + { + if (dbus_message_get_error_name (message) != NULL && + strcmp (dbus_message_get_error_name (message), + rule->d.send.error) != 0) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + continue; + } + } + if (rule->d.send.destination != NULL) { /* receiver can be NULL for messages that are sent to the @@ -856,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); @@ -873,12 +951,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, { BusPolicyRule *rule = link->data; - link = _dbus_list_get_next_link (&policy->rules, link); - - /* Rule is skipped if it specifies a different - * message name from the message, or a different - * origin from the message - */ + link = _dbus_list_get_next_link (&policy->rules, link); if (rule->type != BUS_POLICY_RULE_RECEIVE) { @@ -886,16 +959,77 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, continue; } - if (rule->d.receive.message_name != NULL) + if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID) { - if (!dbus_message_has_name (message, - rule->d.receive.message_name)) + if (dbus_message_get_type (message) != rule->d.receive.message_type) { - _dbus_verbose (" (policy) skipping rule for different message name\n"); + _dbus_verbose (" (policy) skipping rule for different message type\n"); 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) + { + if (dbus_message_get_path (message) != NULL && + strcmp (dbus_message_get_path (message), + rule->d.receive.path) != 0) + { + _dbus_verbose (" (policy) skipping rule for different path\n"); + continue; + } + } + + if (rule->d.receive.interface != NULL) + { + if (dbus_message_get_interface (message) != NULL && + strcmp (dbus_message_get_interface (message), + rule->d.receive.interface) != 0) + { + _dbus_verbose (" (policy) skipping rule for different interface\n"); + continue; + } + } + + if (rule->d.receive.member != NULL) + { + if (dbus_message_get_member (message) != NULL && + strcmp (dbus_message_get_member (message), + rule->d.receive.member) != 0) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + continue; + } + } + + if (rule->d.receive.error != NULL) + { + if (dbus_message_get_error_name (message) != NULL && + strcmp (dbus_message_get_error_name (message), + rule->d.receive.error) != 0) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + continue; + } + } + if (rule->d.receive.origin != NULL) { /* sender can be NULL for messages that originate from the @@ -937,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 940085ee..63981cc0 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -54,16 +54,27 @@ struct BusPolicyRule { struct { - /* either can be NULL meaning "any" */ - char *message_name; + /* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */ + int message_type; + /* any of these can be NULL meaning "any" */ + char *path; + char *interface; + char *member; + char *error; char *destination; } send; struct { - /* either can be NULL meaning "any" */ - char *message_name; + /* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */ + int message_type; + /* any of these can be NULL meaning "any" */ + char *path; + char *interface; + char *member; + char *error; char *origin; + unsigned int eavesdrop : 1; } receive; struct @@ -124,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/services.c b/bus/services.c index 5148f1f1..84cabe21 100644 --- a/bus/services.c +++ b/bus/services.c @@ -417,10 +417,14 @@ bus_service_relink (BusService *service, bus_service_ref (service); } +/** + * Data used to represent an ownership cancellation in + * a bus transaction. + */ typedef struct { - DBusConnection *connection; - BusService *service; + DBusConnection *connection; /**< the connection */ + BusService *service; /**< service to cancel ownership of */ } OwnershipCancelData; static void diff --git a/bus/session.conf.in b/bus/session.conf.in index 673d8739..34d2492c 100644 --- a/bus/session.conf.in +++ b/bus/session.conf.in @@ -13,11 +13,14 @@ <servicedir>@EXPANDED_LIBDIR@/dbus-1.0/services</servicedir> <policy context="default"> - <!-- Allow everything --> - <allow send="*"/> - <allow receive="*"/> + <!-- Allow everything to be sent --> + <allow send_destination="*"/> + <!-- Allow everything to be received --> + <allow eavesdrop="true"/> + <!-- Allow anyone to own anything --> <allow own="*"/> - <allow user="*"/> + <!-- Allow any user to connect --> + <allow user="*"/> </policy> <!-- This is included last so local configuration can override what's diff --git a/bus/signals.c b/bus/signals.c new file mode 100644 index 00000000..30d977c3 --- /dev/null +++ b/bus/signals.c @@ -0,0 +1,778 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* signals.c Bus signal connection implementation + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "signals.h" +#include "services.h" +#include "utils.h" + +struct BusMatchRule +{ + int refcount; /**< reference count */ + + DBusConnection *matches_go_to; /**< Owner of the rule */ + + unsigned int flags; /**< BusMatchFlags */ + + int message_type; + char *interface; + char *member; + char *sender; + char *destination; + char *path; +}; + +BusMatchRule* +bus_match_rule_new (DBusConnection *matches_go_to) +{ + BusMatchRule *rule; + + rule = dbus_new0 (BusMatchRule, 1); + if (rule == NULL) + return NULL; + + rule->refcount = 1; + rule->matches_go_to = matches_go_to; + + return rule; +} + +void +bus_match_rule_ref (BusMatchRule *rule) +{ + _dbus_assert (rule->refcount > 0); + + rule->refcount += 1; +} + +void +bus_match_rule_unref (BusMatchRule *rule) +{ + _dbus_assert (rule->refcount > 0); + + rule->refcount -= 1; + if (rule->refcount == 0) + { + dbus_free (rule->interface); + dbus_free (rule->member); + dbus_free (rule->sender); + dbus_free (rule->destination); + dbus_free (rule->path); + dbus_free (rule); + } +} + +#ifdef DBUS_ENABLE_VERBOSE_MODE +static char* +match_rule_to_string (BusMatchRule *rule) +{ + DBusString str; + char *ret; + + if (!_dbus_string_init (&str)) + { + char *s; + while ((s = _dbus_strdup ("nomem")) == NULL) + ; /* only OK for debug spew... */ + return s; + } + + if (rule->flags & BUS_MATCH_MESSAGE_TYPE) + { + /* FIXME make type readable */ + if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_INTERFACE) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_MEMBER) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "member='%s'", rule->member)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_PATH) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "path='%s'", rule->path)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_SENDER) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_DESTINATION) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination)) + goto nomem; + } + + if (!_dbus_string_steal_data (&str, &ret)) + goto nomem; + + _dbus_string_free (&str); + return ret; + + nomem: + _dbus_string_free (&str); + { + char *s; + while ((s = _dbus_strdup ("nomem")) == NULL) + ; /* only OK for debug spew... */ + return s; + } +} +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + +dbus_bool_t +bus_match_rule_set_message_type (BusMatchRule *rule, + int type) +{ + rule->flags |= BUS_MATCH_MESSAGE_TYPE; + + rule->message_type = type; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_interface (BusMatchRule *rule, + const char *interface) +{ + char *new; + + _dbus_assert (interface != NULL); + + new = _dbus_strdup (interface); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_INTERFACE; + dbus_free (rule->interface); + rule->interface = new; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_member (BusMatchRule *rule, + const char *member) +{ + char *new; + + _dbus_assert (member != NULL); + + new = _dbus_strdup (member); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_MEMBER; + dbus_free (rule->member); + rule->member = new; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_sender (BusMatchRule *rule, + const char *sender) +{ + char *new; + + _dbus_assert (sender != NULL); + + new = _dbus_strdup (sender); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_SENDER; + dbus_free (rule->sender); + rule->sender = new; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_destination (BusMatchRule *rule, + const char *destination) +{ + char *new; + + _dbus_assert (destination != NULL); + + new = _dbus_strdup (destination); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_DESTINATION; + dbus_free (rule->destination); + rule->destination = new; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_path (BusMatchRule *rule, + const char *path) +{ + char *new; + + _dbus_assert (path != NULL); + + new = _dbus_strdup (path); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_PATH; + dbus_free (rule->path); + rule->path = new; + + return TRUE; +} + +/* + * The format is comma-separated with strings quoted with single quotes + * as for the shell (to escape a literal single quote, use '\''). + * + * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo', + * path='/bar/foo',destination=':452345-34' + * + */ +BusMatchRule* +bus_match_rule_parse (DBusConnection *matches_go_to, + const DBusString *rule_text, + DBusError *error) +{ + BusMatchRule *rule; + + rule = bus_match_rule_new (matches_go_to); + if (rule == NULL) + goto oom; + + /* FIXME implement for real */ + + if (!bus_match_rule_set_message_type (rule, + DBUS_MESSAGE_TYPE_SIGNAL)) + goto oom; + + return rule; + + oom: + if (rule) + bus_match_rule_unref (rule); + BUS_SET_OOM (error); + return NULL; +} + +struct BusMatchmaker +{ + int refcount; + + DBusList *all_rules; +}; + +BusMatchmaker* +bus_matchmaker_new (void) +{ + BusMatchmaker *matchmaker; + + matchmaker = dbus_new0 (BusMatchmaker, 1); + if (matchmaker == NULL) + return NULL; + + matchmaker->refcount = 1; + + return matchmaker; +} + +void +bus_matchmaker_ref (BusMatchmaker *matchmaker) +{ + _dbus_assert (matchmaker->refcount > 0); + + matchmaker->refcount += 1; +} + +void +bus_matchmaker_unref (BusMatchmaker *matchmaker) +{ + _dbus_assert (matchmaker->refcount > 0); + + matchmaker->refcount -= 1; + if (matchmaker->refcount == 0) + { + while (matchmaker->all_rules != NULL) + { + BusMatchRule *rule; + + rule = matchmaker->all_rules->data; + bus_match_rule_unref (rule); + _dbus_list_remove_link (&matchmaker->all_rules, + matchmaker->all_rules); + } + + dbus_free (matchmaker); + } +} + +/* The rule can't be modified after it's added. */ +dbus_bool_t +bus_matchmaker_add_rule (BusMatchmaker *matchmaker, + BusMatchRule *rule) +{ + _dbus_assert (bus_connection_is_active (rule->matches_go_to)); + + if (!_dbus_list_append (&matchmaker->all_rules, rule)) + return FALSE; + + if (!bus_connection_add_match_rule (rule->matches_go_to, rule)) + { + _dbus_list_remove_last (&matchmaker->all_rules, rule); + return FALSE; + } + + bus_match_rule_ref (rule); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + char *s = match_rule_to_string (rule); + + _dbus_verbose ("Added match rule %s to connection %p\n", + s, rule->matches_go_to); + dbus_free (s); + } +#endif + + return TRUE; +} + +static dbus_bool_t +match_rule_equal (BusMatchRule *a, + BusMatchRule *b) +{ + if (a->flags != b->flags) + return FALSE; + + if ((a->flags & BUS_MATCH_MESSAGE_TYPE) && + a->message_type != b->message_type) + return FALSE; + + if ((a->flags & BUS_MATCH_MEMBER) && + strcmp (a->member, b->member) != 0) + return FALSE; + + if ((a->flags & BUS_MATCH_PATH) && + strcmp (a->path, b->path) != 0) + return FALSE; + + if ((a->flags & BUS_MATCH_INTERFACE) && + strcmp (a->interface, b->interface) != 0) + return FALSE; + + if ((a->flags & BUS_MATCH_SENDER) && + strcmp (a->sender, b->sender) != 0) + return FALSE; + + if ((a->flags & BUS_MATCH_DESTINATION) && + strcmp (a->destination, b->destination) != 0) + return FALSE; + + return TRUE; +} + +static void +bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker, + DBusList *link) +{ + BusMatchRule *rule = link->data; + + bus_connection_remove_match_rule (rule->matches_go_to, rule); + _dbus_list_remove_link (&matchmaker->all_rules, link); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + char *s = match_rule_to_string (rule); + + _dbus_verbose ("Removed match rule %s for connection %p\n", + s, rule->matches_go_to); + dbus_free (s); + } +#endif + + bus_match_rule_unref (rule); +} + +void +bus_matchmaker_remove_rule (BusMatchmaker *matchmaker, + BusMatchRule *rule) +{ + bus_connection_remove_match_rule (rule->matches_go_to, rule); + _dbus_list_remove (&matchmaker->all_rules, rule); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + char *s = match_rule_to_string (rule); + + _dbus_verbose ("Removed match rule %s for connection %p\n", + s, rule->matches_go_to); + dbus_free (s); + } +#endif + + bus_match_rule_unref (rule); +} + +/* Remove a single rule which is equal to the given rule by value */ +dbus_bool_t +bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker, + BusMatchRule *value, + DBusError *error) +{ + /* FIXME this is an unoptimized linear scan */ + + DBusList *link; + + /* we traverse backward because bus_connection_remove_match_rule() + * removes the most-recently-added rule + */ + link = _dbus_list_get_last_link (&matchmaker->all_rules); + while (link != NULL) + { + BusMatchRule *rule; + DBusList *prev; + + rule = link->data; + prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link); + + if (match_rule_equal (rule, value)) + { + bus_matchmaker_remove_rule_link (matchmaker, link); + break; + } + + link = prev; + } + + if (link == NULL) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND, + "The given match rule wasn't found and can't be removed"); + return FALSE; + } + + return TRUE; +} + +void +bus_matchmaker_disconnected (BusMatchmaker *matchmaker, + DBusConnection *disconnected) +{ + DBusList *link; + + /* FIXME + * + * This scans all match rules on the bus. We could avoid that + * for the rules belonging to the connection, since we keep + * a list of those; but for the rules that just refer to + * the connection we'd need to do something more elaborate. + * + */ + + _dbus_assert (bus_connection_is_active (disconnected)); + + link = _dbus_list_get_first_link (&matchmaker->all_rules); + while (link != NULL) + { + BusMatchRule *rule; + DBusList *next; + + rule = link->data; + next = _dbus_list_get_next_link (&matchmaker->all_rules, link); + + if (rule->matches_go_to == disconnected) + { + bus_matchmaker_remove_rule_link (matchmaker, link); + } + else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') || + ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':')) + { + /* The rule matches to/from a base service, see if it's the + * one being disconnected, since we know this service name + * will never be recycled. + */ + const char *name; + + name = bus_connection_get_name (disconnected); + _dbus_assert (name != NULL); /* because we're an active connection */ + + if (((rule->flags & BUS_MATCH_SENDER) && + strcmp (rule->sender, name) == 0) || + ((rule->flags & BUS_MATCH_DESTINATION) && + strcmp (rule->destination, name) == 0)) + { + bus_matchmaker_remove_rule_link (matchmaker, link); + } + } + + link = next; + } +} + +static dbus_bool_t +connection_is_primary_owner (DBusConnection *connection, + const char *service_name) +{ + BusService *service; + DBusString str; + BusRegistry *registry; + + registry = bus_connection_get_registry (connection); + + _dbus_string_init_const (&str, service_name); + service = bus_registry_lookup (registry, &str); + + if (service == NULL) + return FALSE; /* Service doesn't exist so connection can't own it. */ + + return bus_service_get_primary_owner (service) == connection; +} + +static dbus_bool_t +match_rule_matches (BusMatchRule *rule, + BusConnections *connections, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message) +{ + /* All features of the match rule are AND'd together, + * so FALSE if any of them don't match. + */ + + if (rule->flags & BUS_MATCH_MESSAGE_TYPE) + { + _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID); + + if (rule->message_type != dbus_message_get_type (message)) + return FALSE; + } + + if (rule->flags & BUS_MATCH_INTERFACE) + { + const char *iface; + + _dbus_assert (rule->interface != NULL); + + iface = dbus_message_get_interface (message); + if (iface == NULL) + return FALSE; + + if (strcmp (iface, rule->interface) != 0) + return FALSE; + } + + if (rule->flags & BUS_MATCH_MEMBER) + { + const char *member; + + _dbus_assert (rule->member != NULL); + + member = dbus_message_get_member (message); + if (member == NULL) + return FALSE; + + if (strcmp (member, rule->member) != 0) + return FALSE; + } + + if (rule->flags & BUS_MATCH_SENDER) + { + _dbus_assert (rule->sender != NULL); + + if (!connection_is_primary_owner (sender, rule->sender)) + return FALSE; + } + + if (rule->flags & BUS_MATCH_DESTINATION) + { + const char *destination; + + _dbus_assert (rule->destination != NULL); + + if (addressed_recipient == NULL) + return FALSE; + + destination = dbus_message_get_destination (message); + if (destination == NULL) + return FALSE; + + if (!connection_is_primary_owner (addressed_recipient, rule->destination)) + return FALSE; + } + + if (rule->flags & BUS_MATCH_PATH) + { + const char *path; + + _dbus_assert (rule->path != NULL); + + path = dbus_message_get_path (message); + if (path == NULL) + return FALSE; + + if (strcmp (path, rule->path) != 0) + return FALSE; + } + + return TRUE; +} + +dbus_bool_t +bus_matchmaker_get_recipients (BusMatchmaker *matchmaker, + BusConnections *connections, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + DBusList **recipients_p) +{ + /* FIXME for now this is a wholly unoptimized linear search */ + /* Guessing the important optimization is to skip the signal-related + * match lists when processing method call and exception messages. + * So separate match rule lists for signals? + */ + + DBusList *link; + + _dbus_assert (*recipients_p == NULL); + + /* This avoids sending same message to the same connection twice. + * Purpose of the stamp instead of a bool is to avoid iterating over + * all connections resetting the bool each time. + */ + bus_connections_increment_stamp (connections); + + /* addressed_recipient is already receiving the message, don't add to list. + * NULL addressed_recipient means either bus driver, or this is a signal + * and thus lacks a specific addressed_recipient. + */ + if (addressed_recipient != NULL) + bus_connection_mark_stamp (addressed_recipient); + + link = _dbus_list_get_first_link (&matchmaker->all_rules); + while (link != NULL) + { + BusMatchRule *rule; + + rule = link->data; + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + char *s = match_rule_to_string (rule); + + _dbus_verbose ("Checking whether message matches rule %s for connection %p\n", + s, rule->matches_go_to); + dbus_free (s); + } +#endif + + if (match_rule_matches (rule, connections, + sender, addressed_recipient, message)) + { + _dbus_verbose ("Rule matched\n"); + + /* Append to the list if we haven't already */ + if (bus_connection_mark_stamp (rule->matches_go_to)) + { + if (!_dbus_list_append (recipients_p, rule->matches_go_to)) + goto nomem; + } +#ifdef DBUS_ENABLE_VERBOSE_MODE + else + { + _dbus_verbose ("Connection already receiving this message, so not adding again\n"); + } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + } + + link = _dbus_list_get_next_link (&matchmaker->all_rules, link); + } + + return TRUE; + + nomem: + _dbus_list_clear (recipients_p); + return FALSE; +} + +#ifdef DBUS_BUILD_TESTS +#include "test.h" + +dbus_bool_t +bus_signals_test (const DBusString *test_data_dir) +{ + BusMatchmaker *matchmaker; + + matchmaker = bus_matchmaker_new (); + bus_matchmaker_ref (matchmaker); + bus_matchmaker_unref (matchmaker); + bus_matchmaker_unref (matchmaker); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ + diff --git a/bus/signals.h b/bus/signals.h new file mode 100644 index 00000000..fab018ae --- /dev/null +++ b/bus/signals.h @@ -0,0 +1,83 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* signals.h Bus signal connection implementation + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef BUS_SIGNALS_H +#define BUS_SIGNALS_H + +#include <dbus/dbus.h> +#include <dbus/dbus-string.h> +#include <dbus/dbus-sysdeps.h> +#include "connection.h" + +typedef enum +{ + BUS_MATCH_MESSAGE_TYPE = 1 << 0, + BUS_MATCH_INTERFACE = 1 << 1, + BUS_MATCH_MEMBER = 1 << 2, + BUS_MATCH_SENDER = 1 << 3, + BUS_MATCH_DESTINATION = 1 << 4, + BUS_MATCH_PATH = 1 << 5 +} BusMatchFlags; + +BusMatchRule* bus_match_rule_new (DBusConnection *matches_go_to); +void bus_match_rule_ref (BusMatchRule *rule); +void bus_match_rule_unref (BusMatchRule *rule); + +dbus_bool_t bus_match_rule_set_message_type (BusMatchRule *rule, + int type); +dbus_bool_t bus_match_rule_set_interface (BusMatchRule *rule, + const char *interface); +dbus_bool_t bus_match_rule_set_member (BusMatchRule *rule, + const char *member); +dbus_bool_t bus_match_rule_set_sender (BusMatchRule *rule, + const char *sender); +dbus_bool_t bus_match_rule_set_destination (BusMatchRule *rule, + const char *destination); +dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule, + const char *path); + +BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to, + const DBusString *rule_text, + DBusError *error); + +BusMatchmaker* bus_matchmaker_new (void); +void bus_matchmaker_ref (BusMatchmaker *matchmaker); +void bus_matchmaker_unref (BusMatchmaker *matchmaker); + +dbus_bool_t bus_matchmaker_add_rule (BusMatchmaker *matchmaker, + BusMatchRule *rule); +dbus_bool_t bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker, + BusMatchRule *value, + DBusError *error); +void bus_matchmaker_remove_rule (BusMatchmaker *matchmaker, + BusMatchRule *rule); +void bus_matchmaker_disconnected (BusMatchmaker *matchmaker, + DBusConnection *disconnected); +dbus_bool_t bus_matchmaker_get_recipients (BusMatchmaker *matchmaker, + BusConnections *connections, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + DBusList **recipients_p); + +#endif /* BUS_SIGNALS_H */ diff --git a/bus/system.conf.in b/bus/system.conf.in index 476a87a6..8e2dbda9 100644 --- a/bus/system.conf.in +++ b/bus/system.conf.in @@ -34,16 +34,16 @@ <policy context="default"> <!-- Deny everything then punch holes --> - <deny send="*"/> - <deny receive="*"/> + <deny send_interface="*"/> + <deny receive_interface="*"/> <deny own="*"/> <!-- But allow all users to connect --> <allow user="*"/> <!-- Allow anyone to talk to the message bus --> <!-- FIXME I think currently these allow rules are always implicit even if they aren't in here --> - <allow send_to="org.freedesktop.DBus"/> - <allow receive_from="org.freedesktop.DBus"/> + <allow send_destination="org.freedesktop.DBus"/> + <allow receive_sender="org.freedesktop.DBus"/> </policy> <!-- Config files are placed here that among other things, punch diff --git a/bus/test-main.c b/bus/test-main.c index c433075f..3f280d4e 100644 --- a/bus/test-main.c +++ b/bus/test-main.c @@ -89,6 +89,12 @@ main (int argc, char **argv) check_memleaks (argv[0]); + printf ("%s: Running signals test\n", argv[0]); + if (!bus_signals_test (&test_data_dir)) + die ("signals"); + + check_memleaks (argv[0]); + printf ("%s: Running SHA1 connection test\n", argv[0]); if (!bus_dispatch_sha1_test (&test_data_dir)) die ("sha1"); @@ -102,11 +102,15 @@ remove_client_timeout (DBusTimeout *timeout, } static DBusHandlerResult -client_disconnect_handler (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message, - void *user_data) +client_disconnect_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) { + if (!dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + _dbus_verbose ("Removing client %p in disconnect handler\n", connection); @@ -120,42 +124,19 @@ client_disconnect_handler (DBusMessageHandler *handler, client_loop = NULL; } - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; -} - -static dbus_int32_t handler_slot = -1; - -static void -free_handler (void *data) -{ - DBusMessageHandler *handler = data; - - dbus_message_handler_unref (handler); - dbus_connection_free_data_slot (&handler_slot); + return DBUS_HANDLER_RESULT_HANDLED; } dbus_bool_t bus_setup_debug_client (DBusConnection *connection) { - DBusMessageHandler *disconnect_handler; - const char *to_handle[] = { DBUS_MESSAGE_LOCAL_DISCONNECT }; - dbus_bool_t retval; - - disconnect_handler = dbus_message_handler_new (client_disconnect_handler, - NULL, NULL); + dbus_bool_t retval; - if (disconnect_handler == NULL) + if (!dbus_connection_add_filter (connection, + client_disconnect_filter, + NULL, NULL)) return FALSE; - if (!dbus_connection_register_handler (connection, - disconnect_handler, - to_handle, - _DBUS_N_ELEMENTS (to_handle))) - { - dbus_message_handler_unref (disconnect_handler); - return FALSE; - } - retval = FALSE; if (client_loop == NULL) @@ -182,25 +163,15 @@ bus_setup_debug_client (DBusConnection *connection) if (!_dbus_list_append (&clients, connection)) goto out; - - if (!dbus_connection_allocate_data_slot (&handler_slot)) - goto out; - - /* Set up handler to be destroyed */ - if (!dbus_connection_set_data (connection, handler_slot, - disconnect_handler, - free_handler)) - { - dbus_connection_free_data_slot (&handler_slot); - goto out; - } retval = TRUE; out: if (!retval) { - dbus_message_handler_unref (disconnect_handler); /* unregisters it */ + dbus_connection_remove_filter (connection, + client_disconnect_filter, + NULL); dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL); @@ -36,6 +36,7 @@ dbus_bool_t bus_dispatch_test (const DBusString *test_data_d dbus_bool_t bus_dispatch_sha1_test (const DBusString *test_data_dir); dbus_bool_t bus_policy_test (const DBusString *test_data_dir); dbus_bool_t bus_config_parser_test (const DBusString *test_data_dir); +dbus_bool_t bus_signals_test (const DBusString *test_data_dir); dbus_bool_t bus_setup_debug_client (DBusConnection *connection); void bus_test_clients_foreach (BusConnectionForeachFunction function, void *data); |