Commit a683a80c authored by Havoc Pennington's avatar Havoc Pennington

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)
parent daf8d657
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 \
......
......@@ -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;
}
......
......@@ -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)
......
......@@ -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;
}