mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2025-12-25 16:20:08 +01:00
2003-09-21 Havoc Pennington <hp@pobox.com>
Get matching rules mostly working in the bus; only actually parsing the rule text remains. However, the client side of "signal connections" hasn't been started, this patch is only the bus side. * dbus/dispatch.c: fix for the matching rules changes * bus/driver.c (bus_driver_handle_remove_match) (bus_driver_handle_add_match): send an ack reply from these method calls * glib/dbus-gproxy.c (dbus_gproxy_begin_call): fix order of arguments, reported by Seth Nickell * bus/config-parser.c (append_rule_from_element): support eavesdrop=true|false attribute on policies so match rules can be prevented from snooping on the system bus. * bus/dbus-daemon-1.1.in: consistently use terminology "sender" and "destination" in attribute names; fix some docs bugs; add eavesdrop=true|false attribute * bus/driver.c (bus_driver_handle_add_match) (bus_driver_handle_remove_match): handle AddMatch, RemoveMatch messages * dbus/dbus-protocol.h (DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST): get rid of broadcast service concept, signals are just always broadcast * bus/signals.c, bus/dispatch.c, bus/connection.c, bus/bus.c: mostly implement matching rules stuff (currently only exposed as signal connections)
This commit is contained in:
parent
daf8d6579e
commit
a683a80c40
28 changed files with 1697 additions and 206 deletions
35
ChangeLog
35
ChangeLog
|
|
@ -1,3 +1,38 @@
|
|||
2003-09-21 Havoc Pennington <hp@pobox.com>
|
||||
|
||||
Get matching rules mostly working in the bus; only actually
|
||||
parsing the rule text remains. However, the client side of
|
||||
"signal connections" hasn't been started, this patch is only the
|
||||
bus side.
|
||||
|
||||
* dbus/dispatch.c: fix for the matching rules changes
|
||||
|
||||
* bus/driver.c (bus_driver_handle_remove_match)
|
||||
(bus_driver_handle_add_match): send an ack reply from these
|
||||
method calls
|
||||
|
||||
* glib/dbus-gproxy.c (dbus_gproxy_begin_call): fix order of
|
||||
arguments, reported by Seth Nickell
|
||||
|
||||
* bus/config-parser.c (append_rule_from_element): support
|
||||
eavesdrop=true|false attribute on policies so match rules
|
||||
can be prevented from snooping on the system bus.
|
||||
|
||||
* bus/dbus-daemon-1.1.in: consistently use terminology "sender"
|
||||
and "destination" in attribute names; fix some docs bugs;
|
||||
add eavesdrop=true|false attribute
|
||||
|
||||
* bus/driver.c (bus_driver_handle_add_match)
|
||||
(bus_driver_handle_remove_match): handle AddMatch, RemoveMatch
|
||||
messages
|
||||
|
||||
* dbus/dbus-protocol.h (DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST): get
|
||||
rid of broadcast service concept, signals are just always broadcast
|
||||
|
||||
* bus/signals.c, bus/dispatch.c, bus/connection.c, bus/bus.c:
|
||||
mostly implement matching rules stuff (currently only exposed as signal
|
||||
connections)
|
||||
|
||||
2003-09-21 Mark McLoughlin <mark@skynet.ie>
|
||||
|
||||
* doc/dbus-specification.sgml: Change the header field name
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ BUS_SOURCES= \
|
|||
policy.h \
|
||||
services.c \
|
||||
services.h \
|
||||
signals.c \
|
||||
signals.h \
|
||||
test.c \
|
||||
test.h \
|
||||
utils.c \
|
||||
|
|
|
|||
65
bus/bus.c
65
bus/bus.c
|
|
@ -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,7 +905,7 @@ bus_context_check_security_policy (BusContext *context,
|
|||
/* Policy for inactive connections is that they can only send
|
||||
* the hello message to the bus driver
|
||||
*/
|
||||
if (recipient == NULL &&
|
||||
if (proposed_recipient == NULL &&
|
||||
dbus_message_is_method_call (message,
|
||||
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
|
||||
"Hello"))
|
||||
|
|
@ -897,15 +933,15 @@ bus_context_check_security_policy (BusContext *context,
|
|||
_dbus_assert ((sender != NULL && sender_policy != NULL) ||
|
||||
(sender == NULL && sender_policy == NULL));
|
||||
|
||||
if (recipient != NULL)
|
||||
if (proposed_recipient != NULL)
|
||||
{
|
||||
/* only the bus driver can send to an inactive recipient (as it
|
||||
* owns no services, so other apps can't address it). Inactive
|
||||
* recipients can receive any message.
|
||||
*/
|
||||
if (bus_connection_is_active (recipient))
|
||||
if (bus_connection_is_active (proposed_recipient))
|
||||
{
|
||||
recipient_policy = bus_connection_get_policy (recipient);
|
||||
recipient_policy = bus_connection_get_policy (proposed_recipient);
|
||||
_dbus_assert (recipient_policy != NULL);
|
||||
}
|
||||
else if (sender == NULL)
|
||||
|
|
@ -922,13 +958,13 @@ bus_context_check_security_policy (BusContext *context,
|
|||
else
|
||||
recipient_policy = NULL;
|
||||
|
||||
_dbus_assert ((recipient != NULL && recipient_policy != NULL) ||
|
||||
(recipient != NULL && sender == NULL && recipient_policy == NULL) ||
|
||||
(recipient == NULL && recipient_policy == NULL));
|
||||
_dbus_assert ((proposed_recipient != NULL && recipient_policy != NULL) ||
|
||||
(proposed_recipient != NULL && sender == NULL && recipient_policy == NULL) ||
|
||||
(proposed_recipient == NULL && recipient_policy == NULL));
|
||||
|
||||
if (sender_policy &&
|
||||
!bus_client_policy_check_can_send (sender_policy,
|
||||
context->registry, recipient,
|
||||
context->registry, proposed_recipient,
|
||||
message))
|
||||
{
|
||||
const char *dest = dbus_message_get_destination (message);
|
||||
|
|
@ -951,6 +987,7 @@ bus_context_check_security_policy (BusContext *context,
|
|||
if (recipient_policy &&
|
||||
!bus_client_policy_check_can_receive (recipient_policy,
|
||||
context->registry, sender,
|
||||
addressed_recipient, proposed_recipient,
|
||||
message))
|
||||
{
|
||||
const char *dest = dbus_message_get_destination (message);
|
||||
|
|
@ -971,14 +1008,16 @@ bus_context_check_security_policy (BusContext *context,
|
|||
}
|
||||
|
||||
/* See if limits on size have been exceeded */
|
||||
if (recipient &&
|
||||
dbus_connection_get_outgoing_size (recipient) >
|
||||
if (proposed_recipient &&
|
||||
dbus_connection_get_outgoing_size (proposed_recipient) >
|
||||
context->limits.max_outgoing_bytes)
|
||||
{
|
||||
const char *dest = dbus_message_get_destination (message);
|
||||
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
|
||||
"The destination service \"%s\" has a full message queue",
|
||||
dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
|
||||
dest ? dest : (proposed_recipient ?
|
||||
bus_connection_get_name (proposed_recipient) :
|
||||
DBUS_SERVICE_ORG_FREEDESKTOP_DBUS));
|
||||
_dbus_verbose ("security policy disallowing message due to full message queue\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
|||
71
bus/bus.h
71
bus/bus.h
|
|
@ -40,7 +40,8 @@ typedef struct BusPolicyRule BusPolicyRule;
|
|||
typedef struct BusRegistry BusRegistry;
|
||||
typedef struct BusService BusService;
|
||||
typedef struct BusTransaction BusTransaction;
|
||||
|
||||
typedef struct BusMatchmaker BusMatchmaker;
|
||||
typedef struct BusMatchRule BusMatchRule;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -54,40 +55,44 @@ typedef struct
|
|||
int max_connections_per_user; /**< Max number of connections auth'd as same user */
|
||||
int max_pending_activations; /**< Max number of pending activations for the entire bus */
|
||||
int max_services_per_connection; /**< Max number of owned services for a single connection */
|
||||
int max_match_rules_per_connection; /**< Max number of match rules for a single connection */
|
||||
} BusLimits;
|
||||
|
||||
BusContext* bus_context_new (const DBusString *config_file,
|
||||
dbus_bool_t force_fork,
|
||||
int print_addr_fd,
|
||||
int print_pid_fd,
|
||||
DBusError *error);
|
||||
void bus_context_shutdown (BusContext *context);
|
||||
void bus_context_ref (BusContext *context);
|
||||
void bus_context_unref (BusContext *context);
|
||||
const char* bus_context_get_type (BusContext *context);
|
||||
const char* bus_context_get_address (BusContext *context);
|
||||
BusRegistry* bus_context_get_registry (BusContext *context);
|
||||
BusConnections* bus_context_get_connections (BusContext *context);
|
||||
BusActivation* bus_context_get_activation (BusContext *context);
|
||||
DBusLoop* bus_context_get_loop (BusContext *context);
|
||||
DBusUserDatabase* bus_context_get_user_database (BusContext *context);
|
||||
dbus_bool_t bus_context_allow_user (BusContext *context,
|
||||
unsigned long uid);
|
||||
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
|
||||
DBusConnection *connection,
|
||||
DBusError *error);
|
||||
BusContext* bus_context_new (const DBusString *config_file,
|
||||
dbus_bool_t force_fork,
|
||||
int print_addr_fd,
|
||||
int print_pid_fd,
|
||||
DBusError *error);
|
||||
void bus_context_shutdown (BusContext *context);
|
||||
void bus_context_ref (BusContext *context);
|
||||
void bus_context_unref (BusContext *context);
|
||||
const char* bus_context_get_type (BusContext *context);
|
||||
const char* bus_context_get_address (BusContext *context);
|
||||
BusRegistry* bus_context_get_registry (BusContext *context);
|
||||
BusConnections* bus_context_get_connections (BusContext *context);
|
||||
BusActivation* bus_context_get_activation (BusContext *context);
|
||||
BusMatchmaker* bus_context_get_matchmaker (BusContext *context);
|
||||
DBusLoop* bus_context_get_loop (BusContext *context);
|
||||
DBusUserDatabase* bus_context_get_user_database (BusContext *context);
|
||||
dbus_bool_t bus_context_allow_user (BusContext *context,
|
||||
unsigned long uid);
|
||||
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
|
||||
DBusConnection *connection,
|
||||
DBusError *error);
|
||||
int bus_context_get_activation_timeout (BusContext *context);
|
||||
int bus_context_get_auth_timeout (BusContext *context);
|
||||
int bus_context_get_max_completed_connections (BusContext *context);
|
||||
int bus_context_get_max_incomplete_connections (BusContext *context);
|
||||
int bus_context_get_max_connections_per_user (BusContext *context);
|
||||
int bus_context_get_max_pending_activations (BusContext *context);
|
||||
int bus_context_get_max_services_per_connection (BusContext *context);
|
||||
int bus_context_get_max_match_rules_per_connection (BusContext *context);
|
||||
dbus_bool_t bus_context_check_security_policy (BusContext *context,
|
||||
DBusConnection *sender,
|
||||
DBusConnection *addressed_recipient,
|
||||
DBusConnection *proposed_recipient,
|
||||
DBusMessage *message,
|
||||
DBusError *error);
|
||||
|
||||
int bus_context_get_activation_timeout (BusContext *context);
|
||||
int bus_context_get_auth_timeout (BusContext *context);
|
||||
int bus_context_get_max_completed_connections (BusContext *context);
|
||||
int bus_context_get_max_incomplete_connections (BusContext *context);
|
||||
int bus_context_get_max_connections_per_user (BusContext *context);
|
||||
int bus_context_get_max_pending_activations (BusContext *context);
|
||||
int bus_context_get_max_services_per_connection (BusContext *context);
|
||||
dbus_bool_t bus_context_check_security_policy (BusContext *context,
|
||||
DBusConnection *sender,
|
||||
DBusConnection *recipient,
|
||||
DBusMessage *message,
|
||||
DBusError *error);
|
||||
|
||||
#endif /* BUS_BUS_H */
|
||||
|
|
|
|||
|
|
@ -334,6 +334,8 @@ bus_config_parser_new (const DBusString *basedir,
|
|||
|
||||
parser->limits.max_pending_activations = 256;
|
||||
parser->limits.max_services_per_connection = 256;
|
||||
|
||||
parser->limits.max_match_rules_per_connection = 128;
|
||||
|
||||
parser->refcount = 1;
|
||||
|
||||
|
|
@ -837,15 +839,16 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
const char *send_interface;
|
||||
const char *send_member;
|
||||
const char *send_error;
|
||||
const char *send_service;
|
||||
const char *send_destination;
|
||||
const char *send_path;
|
||||
const char *send_type;
|
||||
const char *receive_interface;
|
||||
const char *receive_member;
|
||||
const char *receive_error;
|
||||
const char *receive_service;
|
||||
const char *receive_sender;
|
||||
const char *receive_path;
|
||||
const char *receive_type;
|
||||
const char *eavesdrop;
|
||||
const char *own;
|
||||
const char *user;
|
||||
const char *group;
|
||||
|
|
@ -858,25 +861,26 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
"send_interface", &send_interface,
|
||||
"send_member", &send_member,
|
||||
"send_error", &send_error,
|
||||
"send_service", &send_service,
|
||||
"send_destination", &send_destination,
|
||||
"send_path", &send_path,
|
||||
"send_type", &send_type,
|
||||
"receive_interface", &receive_interface,
|
||||
"receive_member", &receive_member,
|
||||
"receive_error", &receive_error,
|
||||
"receive_service", &receive_service,
|
||||
"receive_sender", &receive_sender,
|
||||
"receive_path", &receive_path,
|
||||
"receive_type", &receive_type,
|
||||
"eavesdrop", &eavesdrop,
|
||||
"own", &own,
|
||||
"user", &user,
|
||||
"group", &group,
|
||||
NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!(send_interface || send_member || send_error || send_service ||
|
||||
if (!(send_interface || send_member || send_error || send_destination ||
|
||||
send_type || send_path ||
|
||||
receive_interface || receive_member || receive_error || receive_service ||
|
||||
receive_type || receive_path ||
|
||||
receive_interface || receive_member || receive_error || receive_sender ||
|
||||
receive_type || receive_path || eavesdrop ||
|
||||
own || user || group))
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
|
|
@ -902,17 +906,20 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
* interface + member
|
||||
* error
|
||||
*
|
||||
* base send_ can combine with send_service, send_path, send_type
|
||||
* base receive_ with receive_service, receive_path, receive_type
|
||||
* base send_ can combine with send_destination, send_path, send_type
|
||||
* base receive_ with receive_sender, receive_path, receive_type, eavesdrop
|
||||
*
|
||||
* user, group, own must occur alone
|
||||
*
|
||||
* Pretty sure the below stuff is broken, FIXME think about it more.
|
||||
*/
|
||||
|
||||
if (((send_interface && send_error) ||
|
||||
(send_interface && receive_interface) ||
|
||||
(send_interface && receive_member) ||
|
||||
(send_interface && receive_error) ||
|
||||
(send_interface && receive_service) ||
|
||||
(send_interface && receive_sender) ||
|
||||
(send_interface && eavesdrop) ||
|
||||
(send_interface && own) ||
|
||||
(send_interface && user) ||
|
||||
(send_interface && group)) ||
|
||||
|
|
@ -921,7 +928,8 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
(send_member && receive_interface) ||
|
||||
(send_member && receive_member) ||
|
||||
(send_member && receive_error) ||
|
||||
(send_member && receive_service) ||
|
||||
(send_member && receive_sender) ||
|
||||
(send_member && eavesdrop) ||
|
||||
(send_member && own) ||
|
||||
(send_member && user) ||
|
||||
(send_member && group)) ||
|
||||
|
|
@ -929,23 +937,26 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
((send_error && receive_interface) ||
|
||||
(send_error && receive_member) ||
|
||||
(send_error && receive_error) ||
|
||||
(send_error && receive_service) ||
|
||||
(send_error && receive_sender) ||
|
||||
(send_error && eavesdrop) ||
|
||||
(send_error && own) ||
|
||||
(send_error && user) ||
|
||||
(send_error && group)) ||
|
||||
|
||||
((send_service && receive_interface) ||
|
||||
(send_service && receive_member) ||
|
||||
(send_service && receive_error) ||
|
||||
(send_service && receive_service) ||
|
||||
(send_service && own) ||
|
||||
(send_service && user) ||
|
||||
(send_service && group)) ||
|
||||
((send_destination && receive_interface) ||
|
||||
(send_destination && receive_member) ||
|
||||
(send_destination && receive_error) ||
|
||||
(send_destination && receive_sender) ||
|
||||
(send_destination && eavesdrop) ||
|
||||
(send_destination && own) ||
|
||||
(send_destination && user) ||
|
||||
(send_destination && group)) ||
|
||||
|
||||
((send_type && receive_interface) ||
|
||||
(send_type && receive_member) ||
|
||||
(send_type && receive_error) ||
|
||||
(send_type && receive_service) ||
|
||||
(send_type && receive_sender) ||
|
||||
(send_type && eavesdrop) ||
|
||||
(send_type && own) ||
|
||||
(send_type && user) ||
|
||||
(send_type && group)) ||
|
||||
|
|
@ -953,7 +964,8 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
((send_path && receive_interface) ||
|
||||
(send_path && receive_member) ||
|
||||
(send_path && receive_error) ||
|
||||
(send_path && receive_service) ||
|
||||
(send_path && receive_sender) ||
|
||||
(send_path && eavesdrop) ||
|
||||
(send_path && own) ||
|
||||
(send_path && user) ||
|
||||
(send_path && group)) ||
|
||||
|
|
@ -967,19 +979,22 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
(receive_member && own) ||
|
||||
(receive_member && user) ||
|
||||
(receive_member && group)) ||
|
||||
|
||||
|
||||
((receive_error && own) ||
|
||||
(receive_error && user) ||
|
||||
(receive_error && group)) ||
|
||||
|
||||
((eavesdrop && own) ||
|
||||
(eavesdrop && user) ||
|
||||
(eavesdrop && group)) ||
|
||||
|
||||
((own && user) ||
|
||||
(own && group)) ||
|
||||
|
||||
((user && group)))
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
"Invalid combination of attributes on element <%s>, "
|
||||
"only send_foo/send_service or receive_foo/receive_service may be paired",
|
||||
"Invalid combination of attributes on element <%s>",
|
||||
element_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -991,7 +1006,7 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
*/
|
||||
#define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
|
||||
|
||||
if (send_interface || send_member || send_error || send_service ||
|
||||
if (send_interface || send_member || send_error || send_destination ||
|
||||
send_path || send_type)
|
||||
{
|
||||
int message_type;
|
||||
|
|
@ -1002,8 +1017,8 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
send_member = NULL;
|
||||
if (IS_WILDCARD (send_error))
|
||||
send_error = NULL;
|
||||
if (IS_WILDCARD (send_service))
|
||||
send_service = NULL;
|
||||
if (IS_WILDCARD (send_destination))
|
||||
send_destination = NULL;
|
||||
if (IS_WILDCARD (send_path))
|
||||
send_path = NULL;
|
||||
if (IS_WILDCARD (send_type))
|
||||
|
|
@ -1025,13 +1040,13 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
|
||||
if (rule == NULL)
|
||||
goto nomem;
|
||||
|
||||
|
||||
rule->d.send.message_type = message_type;
|
||||
rule->d.send.path = _dbus_strdup (send_path);
|
||||
rule->d.send.interface = _dbus_strdup (send_interface);
|
||||
rule->d.send.member = _dbus_strdup (send_member);
|
||||
rule->d.send.error = _dbus_strdup (send_error);
|
||||
rule->d.send.destination = _dbus_strdup (send_service);
|
||||
rule->d.send.destination = _dbus_strdup (send_destination);
|
||||
if (send_path && rule->d.send.path == NULL)
|
||||
goto nomem;
|
||||
if (send_interface && rule->d.send.interface == NULL)
|
||||
|
|
@ -1040,11 +1055,11 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
goto nomem;
|
||||
if (send_error && rule->d.send.error == NULL)
|
||||
goto nomem;
|
||||
if (send_service && rule->d.send.destination == NULL)
|
||||
if (send_destination && rule->d.send.destination == NULL)
|
||||
goto nomem;
|
||||
}
|
||||
else if (receive_interface || receive_member || receive_error || receive_service ||
|
||||
receive_path || receive_type)
|
||||
else if (receive_interface || receive_member || receive_error || receive_sender ||
|
||||
receive_path || receive_type || eavesdrop)
|
||||
{
|
||||
int message_type;
|
||||
|
||||
|
|
@ -1054,14 +1069,13 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
receive_member = NULL;
|
||||
if (IS_WILDCARD (receive_error))
|
||||
receive_error = NULL;
|
||||
if (IS_WILDCARD (receive_service))
|
||||
receive_service = NULL;
|
||||
if (IS_WILDCARD (receive_sender))
|
||||
receive_sender = NULL;
|
||||
if (IS_WILDCARD (receive_path))
|
||||
receive_path = NULL;
|
||||
if (IS_WILDCARD (receive_type))
|
||||
receive_type = NULL;
|
||||
|
||||
|
||||
message_type = DBUS_MESSAGE_TYPE_INVALID;
|
||||
if (receive_type != NULL)
|
||||
{
|
||||
|
|
@ -1074,17 +1088,31 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (eavesdrop &&
|
||||
!(strcmp (eavesdrop, "true") == 0 ||
|
||||
strcmp (eavesdrop, "false") == 0))
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
"Bad value \"%s\" for eavesdrop attribute, must be true or false",
|
||||
eavesdrop);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
|
||||
if (rule == NULL)
|
||||
goto nomem;
|
||||
|
||||
if (eavesdrop)
|
||||
rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0);
|
||||
|
||||
rule->d.receive.message_type = message_type;
|
||||
rule->d.receive.path = _dbus_strdup (receive_path);
|
||||
rule->d.receive.interface = _dbus_strdup (receive_interface);
|
||||
rule->d.receive.member = _dbus_strdup (receive_member);
|
||||
rule->d.receive.error = _dbus_strdup (receive_error);
|
||||
rule->d.receive.origin = _dbus_strdup (receive_service);
|
||||
rule->d.receive.origin = _dbus_strdup (receive_sender);
|
||||
if (receive_path && rule->d.receive.path == NULL)
|
||||
goto nomem;
|
||||
if (receive_interface && rule->d.receive.interface == NULL)
|
||||
|
|
@ -1093,7 +1121,7 @@ append_rule_from_element (BusConfigParser *parser,
|
|||
goto nomem;
|
||||
if (receive_error && rule->d.receive.error == NULL)
|
||||
goto nomem;
|
||||
if (receive_service && rule->d.receive.origin == NULL)
|
||||
if (receive_sender && rule->d.receive.origin == NULL)
|
||||
goto nomem;
|
||||
}
|
||||
else if (own)
|
||||
|
|
|
|||
123
bus/connection.c
123
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.
|
||||
*
|
||||
|
|
@ -1024,6 +1083,62 @@ bus_connection_send_oom_error (DBusConnection *connection,
|
|||
d->oom_preallocated = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
bus_connection_add_match_rule_link (DBusConnection *connection,
|
||||
DBusList *link)
|
||||
{
|
||||
BusConnectionData *d;
|
||||
|
||||
d = BUS_CONNECTION_DATA (connection);
|
||||
_dbus_assert (d != NULL);
|
||||
|
||||
_dbus_list_append_link (&d->match_rules, link);
|
||||
|
||||
d->n_match_rules += 1;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
bus_connection_add_match_rule (DBusConnection *connection,
|
||||
BusMatchRule *rule)
|
||||
{
|
||||
DBusList *link;
|
||||
|
||||
link = _dbus_list_alloc_link (rule);
|
||||
|
||||
if (link == NULL)
|
||||
return FALSE;
|
||||
|
||||
bus_connection_add_match_rule_link (connection, link);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
bus_connection_remove_match_rule (DBusConnection *connection,
|
||||
BusMatchRule *rule)
|
||||
{
|
||||
BusConnectionData *d;
|
||||
|
||||
d = BUS_CONNECTION_DATA (connection);
|
||||
_dbus_assert (d != NULL);
|
||||
|
||||
_dbus_list_remove_last (&d->match_rules, rule);
|
||||
|
||||
d->n_match_rules -= 1;
|
||||
_dbus_assert (d->n_match_rules >= 0);
|
||||
}
|
||||
|
||||
int
|
||||
bus_connection_get_n_match_rules (DBusConnection *connection)
|
||||
{
|
||||
BusConnectionData *d;
|
||||
|
||||
d = BUS_CONNECTION_DATA (connection);
|
||||
_dbus_assert (d != NULL);
|
||||
|
||||
return d->n_match_rules;
|
||||
}
|
||||
|
||||
void
|
||||
bus_connection_add_owned_service_link (DBusConnection *connection,
|
||||
DBusList *link)
|
||||
|
|
@ -1092,6 +1207,8 @@ bus_connection_complete (DBusConnection *connection,
|
|||
_dbus_assert (d != NULL);
|
||||
_dbus_assert (d->name == NULL);
|
||||
_dbus_assert (d->policy == NULL);
|
||||
|
||||
_dbus_assert (!bus_connection_is_active (connection));
|
||||
|
||||
if (!_dbus_string_copy_data (name, &d->name))
|
||||
{
|
||||
|
|
@ -1147,6 +1264,8 @@ bus_connection_complete (DBusConnection *connection,
|
|||
|
||||
/* See if we can remove the timeout */
|
||||
bus_connections_expire_incomplete (d->connections);
|
||||
|
||||
_dbus_assert (bus_connection_is_active (connection));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -1327,7 +1446,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
|
|||
* eat it; the driver doesn't care about getting a reply.
|
||||
*/
|
||||
if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
|
||||
NULL, connection, message, NULL))
|
||||
NULL, connection, connection, message, NULL))
|
||||
return TRUE;
|
||||
|
||||
return bus_transaction_send (transaction, connection, message);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -328,26 +328,32 @@ in the config file.
|
|||
|
||||
.TP
|
||||
.I "<deny>"
|
||||
.I "<allow>"
|
||||
|
||||
.PP
|
||||
A <deny> element appears below a <policy> element and prohibits
|
||||
some action. The possible attributes of a <deny> element are:
|
||||
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
|
||||
The possible attributes of these elements are:
|
||||
.nf
|
||||
send_interface="interface_name"
|
||||
send_member="method_or_signal_name"
|
||||
send_error="error_name"
|
||||
send_service="service_name"
|
||||
send_type="method_call|method_return|signal|error"
|
||||
send_destination="service_name"
|
||||
send_type="method_call" | "method_return" | "signal" | "error"
|
||||
send_path="/path/name"
|
||||
|
||||
receive_interface="interface_name"
|
||||
receive_member="method_or_signal_name"
|
||||
receive_error="error_name"
|
||||
receive_service="service_name"
|
||||
receive_type="method_call|method_return|signal|error"
|
||||
receive_sender="service_name"
|
||||
receive_type="method_call" | "method_return" | "signal" | "error"
|
||||
receive_path="/path/name"
|
||||
|
||||
eavesdrop="true" | "false"
|
||||
|
||||
receive="messagename"
|
||||
own="servicename"
|
||||
user="username"
|
||||
group="groupname"
|
||||
|
|
@ -359,8 +365,8 @@ Examples:
|
|||
<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_service="org.freedesktop.System"/>
|
||||
<deny receive_service="org.freedesktop.System"/>
|
||||
<deny send_destination="org.freedesktop.System"/>
|
||||
<deny receive_sender="org.freedesktop.System"/>
|
||||
<deny user="john"/>
|
||||
<deny group="enemies"/>
|
||||
.fi
|
||||
|
|
@ -371,7 +377,7 @@ particular action. If it matches, the action is denied (unless later
|
|||
rules in the config file allow it).
|
||||
|
||||
.PP
|
||||
send_service and receive_service rules mean that messages may not be
|
||||
send_destination and receive_sender rules mean that messages may not be
|
||||
sent to or received from the *owner* of the given service, not that
|
||||
they may not be sent *to that service name*. That is, if a connection
|
||||
owns services A, B, C, and sending to A is denied, sending to B or C
|
||||
|
|
@ -381,6 +387,22 @@ will not work either.
|
|||
The other send_* and receive_* attributes are purely textual/by-value
|
||||
matches against the given field in the message header.
|
||||
|
||||
.PP
|
||||
"Eavesdropping" occurs when an application receives a message that
|
||||
was explicitly addressed to a service the application does not own.
|
||||
Eavesdropping thus only applies to messages that are addressed to
|
||||
services (i.e. it does not apply to signals).
|
||||
|
||||
.PP
|
||||
For <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.
|
||||
|
|
@ -413,13 +435,6 @@ received" are evaluated separately.
|
|||
Be careful with send_interface/receive_interface, because the
|
||||
interface field in messages is optional.
|
||||
|
||||
.TP
|
||||
.I "<allow>"
|
||||
|
||||
.PP
|
||||
Makes an exception to previous <deny> statements. Works
|
||||
just like <deny> but with the inverse meaning.
|
||||
|
||||
.SH AUTHOR
|
||||
See http://www.freedesktop.org/software/dbus/doc/AUTHORS
|
||||
|
||||
|
|
|
|||
312
bus/dispatch.c
312
bus/dispatch.c
|
|
@ -28,36 +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>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BusContext *context;
|
||||
DBusConnection *sender;
|
||||
DBusMessage *message;
|
||||
BusTransaction *transaction;
|
||||
DBusError *error;
|
||||
} SendMessageData;
|
||||
|
||||
static dbus_bool_t
|
||||
send_one_message (DBusConnection *connection, void *data)
|
||||
send_one_message (DBusConnection *connection,
|
||||
BusContext *context,
|
||||
DBusConnection *sender,
|
||||
DBusConnection *addressed_recipient,
|
||||
DBusMessage *message,
|
||||
BusTransaction *transaction,
|
||||
DBusError *error)
|
||||
{
|
||||
SendMessageData *d = data;
|
||||
|
||||
if (!bus_context_check_security_policy (d->context,
|
||||
d->sender,
|
||||
if (!bus_context_check_security_policy (context,
|
||||
sender,
|
||||
addressed_recipient,
|
||||
connection,
|
||||
d->message,
|
||||
message,
|
||||
NULL))
|
||||
return TRUE; /* silently don't send it */
|
||||
|
||||
if (!bus_transaction_send (d->transaction,
|
||||
if (!bus_transaction_send (transaction,
|
||||
connection,
|
||||
d->message))
|
||||
message))
|
||||
{
|
||||
BUS_SET_OOM (d->error);
|
||||
BUS_SET_OOM (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -65,30 +62,60 @@ send_one_message (DBusConnection *connection, void *data)
|
|||
}
|
||||
|
||||
dbus_bool_t
|
||||
bus_dispatch_broadcast_message (BusTransaction *transaction,
|
||||
DBusConnection *sender,
|
||||
DBusMessage *message,
|
||||
DBusError *error)
|
||||
bus_dispatch_matches (BusTransaction *transaction,
|
||||
DBusConnection *sender,
|
||||
DBusConnection *addressed_recipient,
|
||||
DBusMessage *message,
|
||||
DBusError *error)
|
||||
{
|
||||
DBusError tmp_error;
|
||||
SendMessageData d;
|
||||
BusConnections *connections;
|
||||
DBusList *recipients;
|
||||
BusMatchmaker *matchmaker;
|
||||
DBusList *link;
|
||||
BusContext *context;
|
||||
|
||||
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
||||
|
||||
|
||||
/* sender and recipient can both be NULL for the bus driver,
|
||||
* or for signals with no particular recipient
|
||||
*/
|
||||
|
||||
_dbus_assert (sender == NULL || bus_connection_is_active (sender));
|
||||
_dbus_assert (dbus_message_get_sender (message) != NULL);
|
||||
|
||||
connections = bus_transaction_get_connections (transaction);
|
||||
|
||||
dbus_error_init (&tmp_error);
|
||||
d.sender = sender;
|
||||
d.context = bus_transaction_get_context (transaction);
|
||||
d.message = message;
|
||||
d.transaction = transaction;
|
||||
d.error = &tmp_error;
|
||||
|
||||
bus_connections_foreach_active (connections, send_one_message, &d);
|
||||
context = bus_transaction_get_context (transaction);
|
||||
matchmaker = bus_context_get_matchmaker (context);
|
||||
|
||||
recipients = NULL;
|
||||
if (!bus_matchmaker_get_recipients (matchmaker,
|
||||
bus_context_get_connections (context),
|
||||
sender, addressed_recipient, message,
|
||||
&recipients))
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
link = _dbus_list_get_first_link (&recipients);
|
||||
while (link != NULL)
|
||||
{
|
||||
DBusConnection *dest;
|
||||
|
||||
dest = link->data;
|
||||
|
||||
if (!send_one_message (dest, context, sender, addressed_recipient,
|
||||
message, transaction, &tmp_error))
|
||||
break;
|
||||
|
||||
link = _dbus_list_get_next_link (&recipients, link);
|
||||
}
|
||||
|
||||
_dbus_list_clear (&recipients);
|
||||
|
||||
if (dbus_error_is_set (&tmp_error))
|
||||
{
|
||||
dbus_move_error (&tmp_error, error);
|
||||
|
|
@ -107,10 +134,12 @@ bus_dispatch (DBusConnection *connection,
|
|||
BusTransaction *transaction;
|
||||
BusContext *context;
|
||||
DBusHandlerResult result;
|
||||
|
||||
DBusConnection *addressed_recipient;
|
||||
|
||||
result = DBUS_HANDLER_RESULT_HANDLED;
|
||||
|
||||
transaction = NULL;
|
||||
addressed_recipient = NULL;
|
||||
dbus_error_init (&error);
|
||||
|
||||
context = bus_connection_get_context (connection);
|
||||
|
|
@ -143,26 +172,31 @@ bus_dispatch (DBusConnection *connection,
|
|||
}
|
||||
#endif /* DBUS_ENABLE_VERBOSE_MODE */
|
||||
|
||||
/* If service_name is NULL, this is a message to the bus daemon, not
|
||||
* intended to actually go "on the bus"; e.g. a peer-to-peer
|
||||
/* If service_name is NULL, if it's a signal we send it to all
|
||||
* connections with a match rule. If it's not a signal, it goes to
|
||||
* the bus daemon but doesn't go "on the bus"; e.g. a peer-to-peer
|
||||
* ping. Handle these immediately, especially disconnection
|
||||
* messages. There are no security policy checks on these.
|
||||
*/
|
||||
if (service_name == NULL)
|
||||
{
|
||||
{
|
||||
if (dbus_message_is_signal (message,
|
||||
DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
|
||||
"Disconnected"))
|
||||
bus_connection_disconnected (connection);
|
||||
{
|
||||
bus_connection_disconnected (connection);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* DBusConnection also handles some of these automatically, we leave
|
||||
* it to do so.
|
||||
*/
|
||||
result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
goto out;
|
||||
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
|
||||
{
|
||||
/* DBusConnection also handles some of these automatically, we leave
|
||||
* it to do so.
|
||||
*/
|
||||
result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
_dbus_assert (service_name != NULL); /* this message is intended for bus routing */
|
||||
|
||||
/* Create our transaction */
|
||||
transaction = bus_transaction_new (context);
|
||||
|
|
@ -191,11 +225,12 @@ bus_dispatch (DBusConnection *connection,
|
|||
*/
|
||||
service_name = dbus_message_get_destination (message);
|
||||
}
|
||||
|
||||
if (strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0) /* to bus driver */
|
||||
|
||||
if (service_name &&
|
||||
strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0) /* to bus driver */
|
||||
{
|
||||
if (!bus_context_check_security_policy (context,
|
||||
connection, NULL, message, &error))
|
||||
connection, NULL, NULL, message, &error))
|
||||
{
|
||||
_dbus_verbose ("Security policy rejected message\n");
|
||||
goto out;
|
||||
|
|
@ -209,22 +244,16 @@ bus_dispatch (DBusConnection *connection,
|
|||
{
|
||||
_dbus_verbose ("Received message from non-registered client. Disconnecting.\n");
|
||||
dbus_connection_disconnect (connection);
|
||||
goto out;
|
||||
}
|
||||
/* FIXME what if we un-special-case this service and just have a flag
|
||||
* on services that all service owners will get messages to it, not just
|
||||
* the primary owner.
|
||||
*/
|
||||
else if (strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST) == 0) /* spam! */
|
||||
{
|
||||
if (!bus_dispatch_broadcast_message (transaction, connection, message, &error))
|
||||
goto out;
|
||||
}
|
||||
else /* route to named service */
|
||||
else if (service_name != NULL) /* route to named service */
|
||||
{
|
||||
DBusString service_string;
|
||||
BusService *service;
|
||||
BusRegistry *registry;
|
||||
|
||||
_dbus_assert (service_name != NULL);
|
||||
|
||||
registry = bus_connection_get_registry (connection);
|
||||
|
||||
_dbus_string_init_const (&service_string, service_name);
|
||||
|
|
@ -239,24 +268,30 @@ bus_dispatch (DBusConnection *connection,
|
|||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBusConnection *recipient;
|
||||
|
||||
recipient = bus_service_get_primary_owner (service);
|
||||
_dbus_assert (recipient != NULL);
|
||||
{
|
||||
addressed_recipient = bus_service_get_primary_owner (service);
|
||||
_dbus_assert (addressed_recipient != NULL);
|
||||
|
||||
if (!bus_context_check_security_policy (context,
|
||||
connection, recipient, message, &error))
|
||||
connection, addressed_recipient,
|
||||
addressed_recipient,
|
||||
message, &error))
|
||||
goto out;
|
||||
|
||||
/* Dispatch the message */
|
||||
if (!bus_transaction_send (transaction, recipient, message))
|
||||
if (!bus_transaction_send (transaction, addressed_recipient, message))
|
||||
{
|
||||
BUS_SET_OOM (&error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now match the messages against any match rules, which will send
|
||||
* out signals and such. addressed_recipient may == NULL.
|
||||
*/
|
||||
if (!bus_dispatch_matches (transaction, connection, addressed_recipient, message, &error))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (dbus_error_is_set (&error))
|
||||
|
|
@ -673,7 +708,7 @@ check_hello_message (BusContext *context,
|
|||
DBusConnection *connection)
|
||||
{
|
||||
DBusMessage *message;
|
||||
dbus_int32_t serial;
|
||||
dbus_uint32_t serial;
|
||||
dbus_bool_t retval;
|
||||
DBusError error;
|
||||
char *name;
|
||||
|
|
@ -684,6 +719,8 @@ check_hello_message (BusContext *context,
|
|||
name = NULL;
|
||||
acquired = NULL;
|
||||
message = NULL;
|
||||
|
||||
_dbus_verbose ("check_hello_message for %p\n", connection);
|
||||
|
||||
message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
|
||||
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
|
||||
|
|
@ -791,7 +828,7 @@ check_hello_message (BusContext *context,
|
|||
while (!dbus_bus_set_base_service (connection, name))
|
||||
_dbus_wait_for_memory ();
|
||||
|
||||
scd.skip_connection = NULL;
|
||||
scd.skip_connection = connection; /* we haven't done AddMatch so won't get it ourselves */
|
||||
scd.failed = FALSE;
|
||||
scd.expected_service_name = name;
|
||||
bus_test_clients_foreach (check_service_created_foreach,
|
||||
|
|
@ -857,6 +894,126 @@ check_hello_message (BusContext *context,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/* returns TRUE if the correct thing happens,
|
||||
* but the correct thing may include OOM errors.
|
||||
*/
|
||||
static dbus_bool_t
|
||||
check_add_match_all (BusContext *context,
|
||||
DBusConnection *connection)
|
||||
{
|
||||
DBusMessage *message;
|
||||
dbus_bool_t retval;
|
||||
dbus_uint32_t serial;
|
||||
DBusError error;
|
||||
|
||||
retval = FALSE;
|
||||
dbus_error_init (&error);
|
||||
message = NULL;
|
||||
|
||||
_dbus_verbose ("check_add_match_all for %p\n", connection);
|
||||
|
||||
message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
|
||||
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
|
||||
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
|
||||
"AddMatch");
|
||||
|
||||
if (message == NULL)
|
||||
return TRUE;
|
||||
|
||||
if (!dbus_message_append_args (message, DBUS_TYPE_STRING, "", /* FIXME */
|
||||
DBUS_TYPE_INVALID))
|
||||
{
|
||||
dbus_message_unref (message);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!dbus_connection_send (connection, message, &serial))
|
||||
{
|
||||
dbus_message_unref (message);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
dbus_message_unref (message);
|
||||
message = NULL;
|
||||
|
||||
/* send our message */
|
||||
bus_test_run_clients_loop (TRUE);
|
||||
|
||||
dbus_connection_ref (connection); /* because we may get disconnected */
|
||||
block_connection_until_message_from_bus (context, connection);
|
||||
|
||||
if (!dbus_connection_get_is_connected (connection))
|
||||
{
|
||||
_dbus_verbose ("connection was disconnected\n");
|
||||
|
||||
dbus_connection_unref (connection);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
dbus_connection_unref (connection);
|
||||
|
||||
message = pop_message_waiting_for_memory (connection);
|
||||
if (message == NULL)
|
||||
{
|
||||
_dbus_warn ("Did not receive a reply to %s %d on %p\n",
|
||||
"AddMatch", serial, connection);
|
||||
goto out;
|
||||
}
|
||||
|
||||
verbose_message_received (connection, message);
|
||||
|
||||
if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
|
||||
{
|
||||
_dbus_warn ("Message has wrong sender %s\n",
|
||||
dbus_message_get_sender (message) ?
|
||||
dbus_message_get_sender (message) : "(none)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
|
||||
{
|
||||
if (dbus_message_is_error (message,
|
||||
DBUS_ERROR_NO_MEMORY))
|
||||
{
|
||||
; /* good, this is a valid response */
|
||||
}
|
||||
else
|
||||
{
|
||||
warn_unexpected (connection, message, "not this error");
|
||||
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
|
||||
{
|
||||
; /* good, expected */
|
||||
_dbus_assert (dbus_message_get_reply_serial (message) == serial);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn_unexpected (connection, message, "method return for AddMatch");
|
||||
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!check_no_leftovers (context))
|
||||
goto out;
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
out:
|
||||
dbus_error_free (&error);
|
||||
|
||||
if (message)
|
||||
dbus_message_unref (message);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* returns TRUE if the correct thing happens,
|
||||
* but the correct thing may include OOM errors.
|
||||
*/
|
||||
|
|
@ -885,7 +1042,7 @@ check_hello_connection (BusContext *context)
|
|||
|
||||
if (!check_hello_message (context, connection))
|
||||
return FALSE;
|
||||
|
||||
|
||||
if (dbus_bus_get_base_service (connection) == NULL)
|
||||
{
|
||||
/* We didn't successfully register, so we can't
|
||||
|
|
@ -895,6 +1052,9 @@ check_hello_connection (BusContext *context)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!check_add_match_all (context, connection))
|
||||
return FALSE;
|
||||
|
||||
kill_client_connection (context, connection);
|
||||
}
|
||||
|
||||
|
|
@ -911,7 +1071,7 @@ check_nonexistent_service_activation (BusContext *context,
|
|||
DBusConnection *connection)
|
||||
{
|
||||
DBusMessage *message;
|
||||
dbus_int32_t serial;
|
||||
dbus_uint32_t serial;
|
||||
dbus_bool_t retval;
|
||||
DBusError error;
|
||||
|
||||
|
|
@ -1293,7 +1453,7 @@ check_send_exit_to_service (BusContext *context,
|
|||
{
|
||||
dbus_bool_t got_error;
|
||||
DBusMessage *message;
|
||||
dbus_int32_t serial;
|
||||
dbus_uint32_t serial;
|
||||
dbus_bool_t retval;
|
||||
|
||||
_dbus_verbose ("Sending exit message to the test service\n");
|
||||
|
|
@ -1462,7 +1622,7 @@ check_existent_service_activation (BusContext *context,
|
|||
DBusConnection *connection)
|
||||
{
|
||||
DBusMessage *message;
|
||||
dbus_int32_t serial;
|
||||
dbus_uint32_t serial;
|
||||
dbus_bool_t retval;
|
||||
DBusError error;
|
||||
char *base_service;
|
||||
|
|
@ -1676,7 +1836,7 @@ check_segfault_service_activation (BusContext *context,
|
|||
DBusConnection *connection)
|
||||
{
|
||||
DBusMessage *message;
|
||||
dbus_int32_t serial;
|
||||
dbus_uint32_t serial;
|
||||
dbus_bool_t retval;
|
||||
DBusError error;
|
||||
|
||||
|
|
@ -1877,6 +2037,9 @@ bus_dispatch_test (const DBusString *test_data_dir)
|
|||
|
||||
if (!check_hello_message (context, foo))
|
||||
_dbus_assert_not_reached ("hello message failed");
|
||||
|
||||
if (!check_add_match_all (context, foo))
|
||||
_dbus_assert_not_reached ("AddMatch message failed");
|
||||
|
||||
bar = dbus_connection_open ("debug-pipe:name=test-server", &error);
|
||||
if (bar == NULL)
|
||||
|
|
@ -1887,6 +2050,9 @@ bus_dispatch_test (const DBusString *test_data_dir)
|
|||
|
||||
if (!check_hello_message (context, bar))
|
||||
_dbus_assert_not_reached ("hello message failed");
|
||||
|
||||
if (!check_add_match_all (context, bar))
|
||||
_dbus_assert_not_reached ("AddMatch message failed");
|
||||
|
||||
baz = dbus_connection_open ("debug-pipe:name=test-server", &error);
|
||||
if (baz == NULL)
|
||||
|
|
@ -1898,6 +2064,9 @@ bus_dispatch_test (const DBusString *test_data_dir)
|
|||
if (!check_hello_message (context, baz))
|
||||
_dbus_assert_not_reached ("hello message failed");
|
||||
|
||||
if (!check_add_match_all (context, baz))
|
||||
_dbus_assert_not_reached ("AddMatch message failed");
|
||||
|
||||
if (!check_no_leftovers (context))
|
||||
{
|
||||
_dbus_warn ("Messages were left over after setting up initial connections");
|
||||
|
|
@ -1954,6 +2123,9 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir)
|
|||
if (!check_hello_message (context, foo))
|
||||
_dbus_assert_not_reached ("hello message failed");
|
||||
|
||||
if (!check_add_match_all (context, foo))
|
||||
_dbus_assert_not_reached ("addmatch message failed");
|
||||
|
||||
if (!check_no_leftovers (context))
|
||||
{
|
||||
_dbus_warn ("Messages were left over after setting up initial SHA-1 connection\n");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
164
bus/driver.c
164
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>
|
||||
|
|
@ -69,7 +70,7 @@ bus_driver_send_service_deleted (const char *service_name,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
|
||||
retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
|
||||
dbus_message_unref (message);
|
||||
|
||||
return retval;
|
||||
|
|
@ -111,7 +112,7 @@ bus_driver_send_service_created (const char *service_name,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
|
||||
retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
|
||||
dbus_message_unref (message);
|
||||
|
||||
return retval;
|
||||
|
|
@ -331,6 +332,7 @@ bus_driver_handle_hello (DBusConnection *connection,
|
|||
|
||||
bus_service_set_prohibit_replacement (service, TRUE);
|
||||
|
||||
_dbus_assert (bus_connection_is_active (connection));
|
||||
retval = TRUE;
|
||||
|
||||
out_0:
|
||||
|
|
@ -600,6 +602,160 @@ bus_driver_handle_activate_service (DBusConnection *connection,
|
|||
return retval;
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
send_ack_reply (DBusConnection *connection,
|
||||
BusTransaction *transaction,
|
||||
DBusMessage *message,
|
||||
DBusError *error)
|
||||
{
|
||||
DBusMessage *reply;
|
||||
|
||||
reply = dbus_message_new_method_return (message);
|
||||
if (reply == NULL)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!bus_transaction_send_from_driver (transaction, connection, reply))
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
dbus_message_unref (reply);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dbus_message_unref (reply);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
bus_driver_handle_add_match (DBusConnection *connection,
|
||||
BusTransaction *transaction,
|
||||
DBusMessage *message,
|
||||
DBusError *error)
|
||||
{
|
||||
BusMatchRule *rule;
|
||||
char *text;
|
||||
DBusString str;
|
||||
BusMatchmaker *matchmaker;
|
||||
|
||||
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
||||
|
||||
text = NULL;
|
||||
rule = NULL;
|
||||
|
||||
if (bus_connection_get_n_match_rules (connection) >=
|
||||
bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction)))
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
|
||||
"Connection \"%s\" is not allowed to add more match rules "
|
||||
"(increase limits in configuration file if required)",
|
||||
bus_connection_is_active (connection) ?
|
||||
bus_connection_get_name (connection) :
|
||||
"(inactive)");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (!dbus_message_get_args (message, error,
|
||||
DBUS_TYPE_STRING, &text,
|
||||
DBUS_TYPE_INVALID))
|
||||
{
|
||||
_dbus_verbose ("No memory to get arguments to AddMatch\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
_dbus_string_init_const (&str, text);
|
||||
|
||||
rule = bus_match_rule_parse (connection, &str, error);
|
||||
if (rule == NULL)
|
||||
goto failed;
|
||||
|
||||
matchmaker = bus_connection_get_matchmaker (connection);
|
||||
|
||||
if (!bus_matchmaker_add_rule (matchmaker, rule))
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (!send_ack_reply (connection, transaction,
|
||||
message, error))
|
||||
{
|
||||
bus_matchmaker_remove_rule (matchmaker, rule);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
bus_match_rule_unref (rule);
|
||||
dbus_free (text);
|
||||
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
_DBUS_ASSERT_ERROR_IS_SET (error);
|
||||
if (rule)
|
||||
bus_match_rule_unref (rule);
|
||||
if (text)
|
||||
dbus_free (text);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
bus_driver_handle_remove_match (DBusConnection *connection,
|
||||
BusTransaction *transaction,
|
||||
DBusMessage *message,
|
||||
DBusError *error)
|
||||
{
|
||||
BusMatchRule *rule;
|
||||
char *text;
|
||||
DBusString str;
|
||||
BusMatchmaker *matchmaker;
|
||||
|
||||
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
||||
|
||||
text = NULL;
|
||||
rule = NULL;
|
||||
|
||||
if (!dbus_message_get_args (message, error,
|
||||
DBUS_TYPE_STRING, &text,
|
||||
DBUS_TYPE_INVALID))
|
||||
{
|
||||
_dbus_verbose ("No memory to get arguments to RemoveMatch\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
_dbus_string_init_const (&str, text);
|
||||
|
||||
rule = bus_match_rule_parse (connection, &str, error);
|
||||
if (rule == NULL)
|
||||
goto failed;
|
||||
|
||||
/* Send the ack before we remove the rule, since the ack is undone
|
||||
* on transaction cancel, but rule removal isn't.
|
||||
*/
|
||||
if (!send_ack_reply (connection, transaction,
|
||||
message, error))
|
||||
goto failed;
|
||||
|
||||
matchmaker = bus_connection_get_matchmaker (connection);
|
||||
|
||||
if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
|
||||
goto failed;
|
||||
|
||||
bus_match_rule_unref (rule);
|
||||
dbus_free (text);
|
||||
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
_DBUS_ASSERT_ERROR_IS_SET (error);
|
||||
if (rule)
|
||||
bus_match_rule_unref (rule);
|
||||
if (text)
|
||||
dbus_free (text);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* For speed it might be useful to sort this in order of
|
||||
* frequency of use (but doesn't matter with only a few items
|
||||
* anyhow)
|
||||
|
|
@ -616,7 +772,9 @@ struct
|
|||
{ "ActivateService", bus_driver_handle_activate_service },
|
||||
{ "Hello", bus_driver_handle_hello },
|
||||
{ "ServiceExists", bus_driver_handle_service_exists },
|
||||
{ "ListServices", bus_driver_handle_list_services }
|
||||
{ "ListServices", bus_driver_handle_list_services },
|
||||
{ "AddMatch", bus_driver_handle_add_match },
|
||||
{ "RemoveMatch", bus_driver_handle_remove_match }
|
||||
};
|
||||
|
||||
dbus_bool_t
|
||||
|
|
|
|||
39
bus/policy.c
39
bus/policy.c
|
|
@ -917,16 +917,33 @@ dbus_bool_t
|
|||
bus_client_policy_check_can_receive (BusClientPolicy *policy,
|
||||
BusRegistry *registry,
|
||||
DBusConnection *sender,
|
||||
DBusConnection *addressed_recipient,
|
||||
DBusConnection *proposed_recipient,
|
||||
DBusMessage *message)
|
||||
{
|
||||
DBusList *link;
|
||||
dbus_bool_t allowed;
|
||||
dbus_bool_t eavesdropping;
|
||||
|
||||
/* NULL sender, proposed_recipient means the bus driver. NULL
|
||||
* addressed_recipient means the message didn't specify an explicit
|
||||
* target. If proposed_recipient is NULL, then addressed_recipient
|
||||
* is also NULL but is implicitly the bus driver.
|
||||
*/
|
||||
|
||||
_dbus_assert (proposed_recipient == NULL ||
|
||||
(dbus_message_get_destination (message) == NULL ||
|
||||
addressed_recipient != NULL));
|
||||
|
||||
eavesdropping =
|
||||
(proposed_recipient == NULL || /* explicitly to bus driver */
|
||||
(addressed_recipient && addressed_recipient != proposed_recipient)); /* explicitly to a different recipient */
|
||||
|
||||
/* policy->rules is in the order the rules appeared
|
||||
* in the config file, i.e. last rule that applies wins
|
||||
*/
|
||||
|
||||
_dbus_verbose (" (policy) checking receive rules\n");
|
||||
_dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
|
||||
|
||||
allowed = FALSE;
|
||||
link = _dbus_list_get_first_link (&policy->rules);
|
||||
|
|
@ -950,6 +967,24 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* for allow, eavesdrop=false means the rule doesn't apply when
|
||||
* eavesdropping. eavesdrop=true means always allow.
|
||||
*/
|
||||
if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop)
|
||||
{
|
||||
_dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* for deny, eavesdrop=true means the rule applies only when
|
||||
* eavesdropping; eavesdrop=false means always deny.
|
||||
*/
|
||||
if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop)
|
||||
{
|
||||
_dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule->d.receive.path != NULL)
|
||||
{
|
||||
|
|
@ -1036,7 +1071,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Use this rule */
|
||||
allowed = rule->allow;
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ struct BusPolicyRule
|
|||
char *member;
|
||||
char *error;
|
||||
char *origin;
|
||||
unsigned int eavesdrop : 1;
|
||||
} receive;
|
||||
|
||||
struct
|
||||
|
|
@ -134,6 +135,8 @@ dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy,
|
|||
dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy,
|
||||
BusRegistry *registry,
|
||||
DBusConnection *sender,
|
||||
DBusConnection *addressed_recipient,
|
||||
DBusConnection *proposed_recipient,
|
||||
DBusMessage *message);
|
||||
dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy,
|
||||
DBusConnection *connection,
|
||||
|
|
|
|||
|
|
@ -14,10 +14,9 @@
|
|||
|
||||
<policy context="default">
|
||||
<!-- Allow everything -->
|
||||
<allow send_interface="*"/>
|
||||
<allow receive_interface="*"/>
|
||||
<allow eavesdrop="true"/>
|
||||
<allow own="*"/>
|
||||
<allow user="*"/>
|
||||
<allow user="*"/>
|
||||
</policy>
|
||||
|
||||
<!-- This is included last so local configuration can override what's
|
||||
|
|
|
|||
774
bus/signals.c
Normal file
774
bus/signals.c
Normal file
|
|
@ -0,0 +1,774 @@
|
|||
/* -*- 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 */
|
||||
|
||||
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 */
|
||||
|
||||
83
bus/signals.h
Normal file
83
bus/signals.h
Normal file
|
|
@ -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 */
|
||||
|
|
@ -42,8 +42,8 @@
|
|||
<!-- 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_service="org.freedesktop.DBus"/>
|
||||
<allow receive_service="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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -53,13 +53,8 @@ struct DBusError
|
|||
};
|
||||
|
||||
#define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed"
|
||||
#define DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND "org.freedesktop.DBus.Activate.ServiceNotFound"
|
||||
#define DBUS_ERROR_SPAWN_EXEC_FAILED "org.freedesktop.DBus.Error.Spawn.ExecFailed"
|
||||
#define DBUS_ERROR_SPAWN_FORK_FAILED "org.freedesktop.DBus.Error.Spawn.ForkFailed"
|
||||
#define DBUS_ERROR_SPAWN_CHILD_EXITED "org.freedesktop.DBus.Error.Spawn.ChildExited"
|
||||
#define DBUS_ERROR_SPAWN_CHILD_SIGNALED "org.freedesktop.DBus.Error.Spawn.ChildSignaled"
|
||||
#define DBUS_ERROR_SPAWN_FAILED "org.freedesktop.DBus.Error.Spawn.Failed"
|
||||
#define DBUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory"
|
||||
#define DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND "org.freedesktop.DBus.Error.ServiceNotFound"
|
||||
#define DBUS_ERROR_SERVICE_DOES_NOT_EXIST "org.freedesktop.DBus.Error.ServiceDoesNotExist"
|
||||
#define DBUS_ERROR_NO_REPLY "org.freedesktop.DBus.Error.NoReply"
|
||||
#define DBUS_ERROR_IO_ERROR "org.freedesktop.DBus.Error.IOError"
|
||||
|
|
@ -77,6 +72,12 @@ struct DBusError
|
|||
#define DBUS_ERROR_FILE_NOT_FOUND "org.freedesktop.DBus.Error.FileNotFound"
|
||||
#define DBUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod"
|
||||
#define DBUS_ERROR_TIMED_OUT "org.freedesktop.DBus.Error.TimedOut"
|
||||
#define DBUS_ERROR_MATCH_RULE_NOT_FOUND "org.freedesktop.DBus.Error.MatchRuleNotFound"
|
||||
#define DBUS_ERROR_SPAWN_EXEC_FAILED "org.freedesktop.DBus.Error.Spawn.ExecFailed"
|
||||
#define DBUS_ERROR_SPAWN_FORK_FAILED "org.freedesktop.DBus.Error.Spawn.ForkFailed"
|
||||
#define DBUS_ERROR_SPAWN_CHILD_EXITED "org.freedesktop.DBus.Error.Spawn.ChildExited"
|
||||
#define DBUS_ERROR_SPAWN_CHILD_SIGNALED "org.freedesktop.DBus.Error.Spawn.ChildSignaled"
|
||||
#define DBUS_ERROR_SPAWN_FAILED "org.freedesktop.DBus.Error.Spawn.Failed"
|
||||
|
||||
void dbus_error_init (DBusError *error);
|
||||
void dbus_error_free (DBusError *error);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include <dbus/dbus-list.h>
|
||||
#include <dbus/dbus-sysdeps.h>
|
||||
|
||||
#define MAINLOOP_SPEW 1
|
||||
#define MAINLOOP_SPEW 0
|
||||
|
||||
struct DBusLoop
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ extern "C" {
|
|||
|
||||
/* Services */
|
||||
#define DBUS_SERVICE_ORG_FREEDESKTOP_DBUS "org.freedesktop.DBus"
|
||||
#define DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST "org.freedesktop.Broadcast"
|
||||
|
||||
/* Paths */
|
||||
#define DBUS_PATH_ORG_FREEDESKTOP_DBUS "/org/freedesktop/DBus"
|
||||
|
|
|
|||
|
|
@ -813,7 +813,9 @@ _dbus_transport_queue_messages (DBusTransport *transport)
|
|||
{
|
||||
DBusDispatchStatus status;
|
||||
|
||||
#if 0
|
||||
_dbus_verbose ("_dbus_transport_queue_messages()\n");
|
||||
#endif
|
||||
|
||||
/* Queue any messages */
|
||||
while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
|
||||
|
|
|
|||
9
doc/TODO
9
doc/TODO
|
|
@ -80,12 +80,15 @@
|
|||
- the invalid messages in the test suite are all useless because
|
||||
they are invalid for the wrong reasons due to protocol changes
|
||||
|
||||
- Nuke the org.freedesktop.Broadcast service; instead,
|
||||
just broadcast messages of type signal
|
||||
|
||||
- I don't want to introduce DBusObject, but refcounting and object
|
||||
data could still be factored out into an internal "base class"
|
||||
perhaps.
|
||||
|
||||
- modify the auth protocol to also support other initial-handshake
|
||||
type of information
|
||||
|
||||
- document the auth protocol as a set of states and transitions, and
|
||||
then reimplement it in those terms
|
||||
|
||||
- Header fields names are required to be aligned on a 4 byte boundary
|
||||
at the moment. No alignment should be neccessary.
|
||||
|
|
|
|||
|
|
@ -188,8 +188,8 @@ dbus_gproxy_begin_call (DBusGProxy *proxy,
|
|||
LOCK_PROXY (proxy);
|
||||
|
||||
message = dbus_message_new_method_call (proxy->service,
|
||||
proxy->interface,
|
||||
proxy->path,
|
||||
proxy->interface,
|
||||
method);
|
||||
if (message == NULL)
|
||||
goto oom;
|
||||
|
|
|
|||
|
|
@ -13,16 +13,16 @@
|
|||
<deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
|
||||
<deny send_path="/foo/bar/SystemObjectThing" send_member="Reboot"/>
|
||||
<deny own="org.freedesktop.System"/>
|
||||
<deny send_service="org.freedesktop.System"/>
|
||||
<deny receive_service="org.freedesktop.System"/>
|
||||
<deny send_destination="org.freedesktop.System"/>
|
||||
<deny receive_sender="org.freedesktop.System"/>
|
||||
<deny user="root"/>
|
||||
<deny group="root"/>
|
||||
<allow send_type="error"/>
|
||||
<allow send_type="method_call"/>
|
||||
<allow send_type="method_return"/>
|
||||
<allow send_type="signal"/>
|
||||
<deny send_service="org.freedesktop.Bar" send_interface="org.freedesktop.Foo"/>
|
||||
<deny send_service="org.freedesktop.Bar" send_interface="org.freedesktop.Foo" send_type="method_call"/>
|
||||
<deny send_destination="org.freedesktop.Bar" send_interface="org.freedesktop.Foo"/>
|
||||
<deny send_destination="org.freedesktop.Bar" send_interface="org.freedesktop.Foo" send_type="method_call"/>
|
||||
</policy>
|
||||
|
||||
<policy context="mandatory">
|
||||
|
|
@ -31,16 +31,16 @@
|
|||
<deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
|
||||
<deny send_path="/foo/bar/SystemObjectThing" send_member="Reboot"/>
|
||||
<deny own="org.freedesktop.System"/>
|
||||
<deny send_service="org.freedesktop.System"/>
|
||||
<deny receive_service="org.freedesktop.System"/>
|
||||
<deny send_destination="org.freedesktop.System"/>
|
||||
<deny receive_sender="org.freedesktop.System"/>
|
||||
<deny user="root"/>
|
||||
<deny group="root"/>
|
||||
<allow send_type="error"/>
|
||||
<allow send_type="method_call"/>
|
||||
<allow send_type="method_return"/>
|
||||
<allow send_type="signal"/>
|
||||
<deny send_service="org.freedesktop.Bar" send_interface="org.freedesktop.Foo"/>
|
||||
<deny send_service="org.freedesktop.Bar" send_interface="org.freedesktop.Foo" send_type="method_call"/>
|
||||
<deny send_destination="org.freedesktop.Bar" send_interface="org.freedesktop.Foo"/>
|
||||
<deny send_destination="org.freedesktop.Bar" send_interface="org.freedesktop.Foo" send_type="method_call"/>
|
||||
</policy>
|
||||
|
||||
<limit name="max_incoming_bytes">5000</limit>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@
|
|||
<!-- Allow any connection to receive the message, but
|
||||
only if the message is sent by the owner of FooService -->
|
||||
<policy context="default">
|
||||
<allow receive_interface="org.foo.FooBroadcastInterface" receive_service="org.foo.FooService"/>
|
||||
<allow receive_interface="org.foo.FooBroadcastInterface" receive_sender="org.foo.FooService"/>
|
||||
</policy>
|
||||
</busconfig>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ main (int argc, char *argv[])
|
|||
DBusMessageIter iter;
|
||||
int i;
|
||||
DBusBusType type = DBUS_BUS_SESSION;
|
||||
const char *dest = DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST;
|
||||
const char *dest = NULL;
|
||||
const char *name = NULL;
|
||||
const char *path = NULL;
|
||||
int message_type = DBUS_MESSAGE_TYPE_SIGNAL;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue