switch (bus_dispatch_matches (transaction,
entry->connection,
addressed_recipient,
- entry->activation_message, error))
+ entry->activation_message, NULL, &error))
{
case BUS_RESULT_TRUE:
break;
if (putback_message->connection == entry->connection)
{
if (!_dbus_connection_putback_message (putback_message->connection, last_inserted_message,
- putback_message->activation_message, error))
+ putback_message->activation_message, &error))
goto error;
last_inserted_message = putback_message->activation_message;
putback_message->is_put_back = TRUE;
/* Wonderful, systemd is connected, let's just send the msg */
switch (bus_dispatch_matches (activation_transaction, NULL,
bus_service_get_primary_owners_connection (service),
- message, error))
+ message, NULL, error))
{
case BUS_RESULT_TRUE:
retval = TRUE;
}
/* See if limits on size have been exceeded */
- if (proposed_recipient &&
- ((dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) ||
- (dbus_connection_get_outgoing_unix_fds (proposed_recipient) > context->limits.max_outgoing_unix_fds)))
- {
- complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
- "Rejected: destination has a full message queue",
- 0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
- error);
- _dbus_verbose ("security policy disallowing message due to full message queue\n");
+ if (!bus_context_check_recipient_message_limits(context, proposed_recipient, sender, message,
+ requested_reply, error))
return BUS_RESULT_FALSE;
- }
/* Record that we will allow a reply here in the future (don't
* bother if the recipient is the bus or this is an eavesdropping
_dbus_server_toggle_all_watches (server, enabled);
}
}
+
+void
+bus_context_complain_about_message (BusContext *context,
+ const char *error_name,
+ const char *complaint,
+ int matched_rules,
+ DBusMessage *message,
+ DBusConnection *sender,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ dbus_bool_t log,
+ const char *privilege,
+ DBusError *error)
+{
+ complain_about_message(context, error_name, complaint, matched_rules, message, sender,
+ proposed_recipient, requested_reply, log, privilege, error);
+}
+
+dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
+ DBusConnection *recipient,
+ DBusConnection *sender,
+ DBusMessage *message,
+ dbus_bool_t requested_reply,
+ DBusError *error)
+
+{
+ if (recipient &&
+ ((dbus_connection_get_outgoing_size (recipient) > context->limits.max_outgoing_bytes) ||
+ (dbus_connection_get_outgoing_unix_fds (recipient) > context->limits.max_outgoing_unix_fds)))
+ {
+ complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
+ "Rejected: destination has a full message queue",
+ 0, message, sender, recipient, requested_reply, TRUE, NULL,
+ error);
+ _dbus_verbose ("security policy disallowing message due to full message queue\n");
+ return FALSE;
+ }
+ return TRUE;
+}
DBusError *error,
BusDeferredMessage **deferred_message);
+dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
+ DBusConnection *recipient,
+ DBusConnection *sender,
+ DBusMessage *message,
+ dbus_bool_t requested_reply,
+ DBusError *error);
+void bus_context_complain_about_message (BusContext *context,
+ const char *error_name,
+ const char *complaint,
+ int matched_rules,
+ DBusMessage *message,
+ DBusConnection *sender,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ dbus_bool_t log,
+ const char *privilege,
+ DBusError *error);
+
+
#endif /* BUS_BUS_H */
DBusConnection *sender;
DBusConnection *proposed_recipient;
DBusConnection *addressed_recipient;
+ dbus_bool_t requested_reply;
+ int matched_rules;
+ const char *privilege;
dbus_bool_t full_dispatch;
BusDeferredMessageStatus status;
BusResult response;
_dbus_connection_enable_dispatch(deferred_message->sender);
}
+static void
+bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
+ BusResult result)
+{
+ int status;
+
+ _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
+
+ if (!bus_connection_is_active(deferred_message->proposed_recipient))
+ return;
+
+ status = deferred_message->status;
+
+ deferred_message->status = 0; /* mark message as not waiting for response */
+ deferred_message->response = result;
+
+ /*
+ * If send rule allows us to send message we still need to check receive rules.
+ */
+ if ((status & BUS_DEFERRED_MESSAGE_CHECK_SEND) && (result == BUS_RESULT_TRUE))
+ {
+ int toggles;
+ BusContext *context;
+ BusRegistry *registry;
+ BusClientPolicy *recipient_policy;
+ BusDeferredMessage *deferred_message_receive;
+
+ context = bus_connection_get_context(deferred_message->proposed_recipient);
+ registry = bus_context_get_registry(context);
+ recipient_policy = bus_connection_get_policy(deferred_message->proposed_recipient);
+
+ deferred_message->response = bus_client_policy_check_can_receive(recipient_policy, registry,
+ deferred_message->requested_reply, deferred_message->sender,
+ deferred_message->addressed_recipient, deferred_message->proposed_recipient, deferred_message->message,
+ &toggles, NULL, &deferred_message_receive);
+ if (deferred_message->response == BUS_RESULT_LATER)
+ {
+ /* replace deferred message associated with send check with the one associated with
+ * receive check */
+ if (!bus_deferred_message_replace(deferred_message, deferred_message_receive))
+ {
+ /* failed to replace deferred message (due to oom). Set it to rejected */
+ deferred_message->response = BUS_RESULT_FALSE;
+ }
+ }
+ }
+
+ bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
+}
+
+static void
+queue_deferred_message_cancel_transaction_hook (void *data)
+{
+ BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
+ bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
+}
+
+
+dbus_bool_t
+bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
+ BusTransaction *transaction,
+ dbus_bool_t full_dispatch,
+ dbus_bool_t prepend)
+{
+ _dbus_assert(deferred_message != NULL);
+ _dbus_assert(deferred_message->proposed_recipient != NULL);
+
+ if (!bus_connection_queue_deferred_message(deferred_message->proposed_recipient,
+ deferred_message, prepend))
+ return FALSE;
+
+ if (!bus_transaction_add_cancel_hook(transaction, queue_deferred_message_cancel_transaction_hook,
+ deferred_message, NULL))
+ {
+ bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
+ return FALSE;
+ }
+ deferred_message->response_callback = bus_check_queued_message_reply_callback;
+ deferred_message->full_dispatch = full_dispatch;
+
+ return TRUE;
+}
+
void
bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
{
deferred_message->response_callback = bus_check_enable_dispatch_callback;
}
+void
+bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
+ dbus_bool_t requested_reply,
+ int matched_rules,
+ const char *privilege)
+{
+ _dbus_assert(deferred_message != NULL);
+
+ deferred_message->requested_reply = requested_reply;
+ deferred_message->matched_rules = matched_rules;
+ deferred_message->privilege = privilege;
+}
+
+
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
const char *privilege);
deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
deferred_message->message = dbus_message_ref(message);
+ deferred_message->requested_reply = FALSE;
+ deferred_message->matched_rules = 0;
+ deferred_message->privilege = NULL;
deferred_message->response = response;
deferred_message->status = 0;
deferred_message->full_dispatch = FALSE;
}
}
+dbus_bool_t
+bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message, DBusError *error)
+{
+ BusContext *context = bus_connection_get_context(deferred_message->proposed_recipient);
+
+ return bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
+ deferred_message->sender, deferred_message->message, deferred_message->requested_reply,
+ error);
+}
+
+dbus_bool_t
+bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, BusTransaction *transaction, DBusError *error)
+{
+ int type = dbus_message_get_type(deferred_message->message);
+ if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
+ deferred_message->sender &&
+ deferred_message->addressed_recipient &&
+ deferred_message->addressed_recipient == deferred_message->proposed_recipient && /* not eavesdropping */
+ !bus_connections_expect_reply (bus_connection_get_connections (deferred_message->sender),
+ transaction,
+ deferred_message->sender, deferred_message->addressed_recipient,
+ deferred_message->message, error))
+ {
+ _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void
+bus_deferred_message_create_error(BusDeferredMessage *deferred_message,
+ const char *error_message, DBusError *error)
+{
+ BusContext *context;
+ _dbus_assert (deferred_message->status == 0 && deferred_message->response == BUS_RESULT_FALSE);
+
+ if (deferred_message->sender == NULL)
+ return; /* error won't be sent to bus driver anyway */
+
+ context = bus_connection_get_context(deferred_message->sender);
+ bus_context_complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected message",
+ deferred_message->matched_rules, deferred_message->message, deferred_message->sender,
+ deferred_message->proposed_recipient, deferred_message->requested_reply, FALSE,
+ deferred_message->privilege, error);
+}
+
+BusResult
+bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
+{
+ BusContext *context = bus_connection_get_context (deferred_message->proposed_recipient);
+ BusTransaction *transaction = bus_transaction_new (context);
+ BusResult result = BUS_RESULT_TRUE;
+ DBusError error;
+
+ if (transaction == NULL)
+ {
+ return BUS_RESULT_FALSE;
+ }
+
+ dbus_error_init(&error);
+
+ if (!deferred_message->full_dispatch)
+ {
+ result = deferred_message->response;
+ switch (result)
+ {
+ case BUS_RESULT_TRUE:
+ if (!bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
+ deferred_message->sender, deferred_message->message, deferred_message->requested_reply, &error))
+ result = BUS_RESULT_FALSE;
+ break;
+ case BUS_RESULT_FALSE:
+ break;
+ case BUS_RESULT_LATER:
+ {
+ BusDeferredMessage *deferred_message2;
+ result = bus_context_check_security_policy (context, transaction,
+ deferred_message->sender,
+ deferred_message->addressed_recipient,
+ deferred_message->proposed_recipient,
+ deferred_message->message, NULL,
+ &deferred_message2);
+
+ if (result == BUS_RESULT_LATER)
+ {
+ /* prepend at recipient */
+ if (!bus_deferred_message_queue_at_recipient(deferred_message2, transaction,
+ FALSE, TRUE))
+ result = BUS_RESULT_FALSE;
+ }
+ }
+ }
+
+ /* silently drop messages on access denial */
+ if (result == BUS_RESULT_TRUE)
+ {
+ if (!bus_transaction_send (transaction, deferred_message->proposed_recipient, deferred_message->message, TRUE))
+ result = BUS_RESULT_FALSE;
+ }
+
+ bus_transaction_execute_and_free(transaction);
+
+ goto out;
+ }
+
+ /* do not attempt to send message if sender has disconnected */
+ if (deferred_message->sender != NULL && !bus_connection_is_active(deferred_message->sender))
+ {
+ bus_transaction_cancel_and_free(transaction);
+ result = BUS_RESULT_FALSE;
+ goto out;
+ }
+
+ result = bus_dispatch_matches(transaction, deferred_message->sender,
+ deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
+
+ if (result == BUS_RESULT_LATER)
+ {
+ /* Message deferring was already done in bus_dispatch_matches */
+ bus_transaction_cancel_and_free(transaction);
+ goto out;
+ }
+
+ /* this part is a copy & paste from bus_dispatch function. Probably can be moved to a function */
+ if (dbus_error_is_set (&error))
+ {
+ if (!dbus_connection_get_is_connected (deferred_message->sender))
+ {
+ /* If we disconnected it, we won't bother to send it any error
+ * messages.
+ */
+ _dbus_verbose ("Not sending error to connection we disconnected\n");
+ }
+ else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+ {
+ bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
+
+ /* cancel transaction due to OOM */
+ if (transaction != NULL)
+ {
+ bus_transaction_cancel_and_free (transaction);
+ transaction = NULL;
+ }
+ }
+ else
+ {
+ /* Try to send the real error, if no mem to do that, send
+ * the OOM error
+ */
+ _dbus_assert (transaction != NULL);
+ if (!bus_transaction_send_error_reply (transaction, deferred_message->sender,
+ &error, deferred_message->message))
+ {
+ bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
+
+ /* cancel transaction due to OOM */
+ if (transaction != NULL)
+ {
+ bus_transaction_cancel_and_free (transaction);
+ transaction = NULL;
+ }
+ }
+ }
+ }
+
+ if (transaction != NULL)
+ {
+ bus_transaction_execute_and_free (transaction);
+ }
+
+out:
+ dbus_error_free(&error);
+
+ return result;
+}
+
+dbus_bool_t
+bus_deferred_message_replace (BusDeferredMessage *old_message, BusDeferredMessage *new_message)
+{
+ if (bus_connection_replace_deferred_message(old_message->proposed_recipient,
+ old_message, new_message))
+ {
+ new_message->response_callback = old_message->response_callback;
+ new_message->full_dispatch = old_message->full_dispatch;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+dbus_bool_t
+bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
+{
+ return deferred_message->status != 0;
+}
+
+DBusConnection *
+bus_deferred_message_get_recipient(BusDeferredMessage *deferred_message)
+{
+ return deferred_message->proposed_recipient;
+}
+
BusDeferredMessageStatus
bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
{
return deferred_message->status;
}
+BusResult
+bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
+{
+ return deferred_message->response;
+}
+
void
bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
BusResult result)
deferred_message->response_callback(deferred_message, result);
}
}
+
BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message);
void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
+BusResult bus_deferred_message_dispatch (BusDeferredMessage *deferred_message);
+dbus_bool_t bus_deferred_message_waits_for_check (BusDeferredMessage *deferred_message);
+DBusConnection *bus_deferred_message_get_recipient (BusDeferredMessage *deferred_message);
void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
BusResult result);
+dbus_bool_t bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
+ BusTransaction *transaction,
+ dbus_bool_t full_dispatch,
+ dbus_bool_t prepend);
+dbus_bool_t bus_deferred_message_replace (BusDeferredMessage *old_message,
+ BusDeferredMessage *new_message);
void bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message);
+BusResult bus_deferred_message_get_response (BusDeferredMessage *deferred_message);
BusDeferredMessageStatus bus_deferred_message_get_status (BusDeferredMessage *deferred_message);
+
+dbus_bool_t bus_deferred_message_expect_method_reply (BusDeferredMessage *deferred_message,
+ BusTransaction *transaction,
+ DBusError *error);
+void bus_deferred_message_create_error (BusDeferredMessage *deferred_message,
+ const char *error_message,
+ DBusError *error);
+void bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
+ dbus_bool_t requested_reply,
+ int matched_rules,
+ const char *privilege);
+dbus_bool_t bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message,
+ DBusError *error);
+
+
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
extern dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
const char *privilege);
#include "expirelist.h"
#include "selinux.h"
#include "apparmor.h"
+#include "check.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-timeout.h>
#include <dbus/dbus-connection-internal.h>
#include <dbus/dbus-internals.h>
+#include <dbus/dbus-message-internal.h>
#ifdef DBUS_ENABLE_CYNARA
#include <stdlib.h>
#include <cynara-session.h>
DBusMessage *oom_message;
DBusPreallocatedSend *oom_preallocated;
BusClientPolicy *policy;
+ DBusList *deferred_messages; /**< Queue of messages deferred due to pending policy check */
char *cached_loginfo_string;
BusSELinuxID *selinux_id;
bus_transaction_execute_and_free (transaction);
}
+ bus_connection_clear_deferred_messages(connection);
+
bus_dispatch_remove_connection (connection);
/* no more watching */
{
DBusConnection *recipient = link->data;
- if (!bus_transaction_send (transaction, recipient, message))
+ if (!bus_transaction_send (transaction, recipient, message, FALSE))
goto out;
}
DBusMessage *message)
{
DBusError error = DBUS_ERROR_INIT;
+ BusDeferredMessage *deferred_message;
/* We have to set the sender to the driver, and have
* to check security policy since it was not done in
switch (bus_context_check_security_policy (bus_transaction_get_context (transaction),
transaction,
NULL, connection, connection, message, &error,
- NULL))
+ &deferred_message))
{
case BUS_RESULT_TRUE:
break;
return TRUE;
break;
case BUS_RESULT_LATER:
- _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
- return TRUE;
- break;
+ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
+ return FALSE;
+ return TRUE; /* pretend to have sent it */
}
- return bus_transaction_send (transaction, connection, message);
+ return bus_transaction_send (transaction, connection, message, FALSE);
}
dbus_bool_t
bus_transaction_send (BusTransaction *transaction,
DBusConnection *connection,
- DBusMessage *message)
+ DBusMessage *message,
+ dbus_bool_t deferred_dispatch)
{
MessageToSend *to_send;
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
-
+
+ if (!deferred_dispatch && d->deferred_messages != NULL)
+ {
+ BusDeferredMessage *deferred_message;
+ dbus_bool_t success;
+ /* sender and addressed recipient are not required at this point as we only need to send message
+ * to a single recipient without performing policy check. */
+ deferred_message = bus_deferred_message_new (message,
+ NULL,
+ NULL,
+ connection,
+ BUS_RESULT_TRUE);
+ if (deferred_message == NULL)
+ return FALSE;
+
+ success = bus_deferred_message_queue_at_recipient(deferred_message, transaction,
+ FALSE, FALSE);
+ bus_deferred_message_unref(deferred_message);
+
+ return success;
+ }
+
to_send = dbus_new (MessageToSend, 1);
if (to_send == NULL)
{
return TRUE;
}
+void
+bus_connection_dispatch_deferred (DBusConnection *connection)
+{
+ BusDeferredMessage *message;
+
+ _dbus_return_if_fail (connection != NULL);
+
+ while ((message = bus_connection_pop_deferred_message(connection)) != NULL)
+ {
+ bus_deferred_message_dispatch(message);
+ bus_deferred_message_unref(message);
+ }
+}
+
+dbus_bool_t
+bus_connection_has_deferred_messages (DBusConnection *connection)
+{
+ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+ return d->deferred_messages != NULL ? TRUE : FALSE;
+}
+
+dbus_bool_t
+bus_connection_queue_deferred_message (DBusConnection *connection,
+ BusDeferredMessage *message,
+ dbus_bool_t prepend)
+{
+ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+ dbus_bool_t success;
+ if (prepend)
+ success = _dbus_list_prepend(&d->deferred_messages, message);
+ else
+ success = _dbus_list_append(&d->deferred_messages, message);
+
+ if (success)
+ {
+ bus_deferred_message_ref(message);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+dbus_bool_t
+bus_connection_replace_deferred_message (DBusConnection *connection,
+ BusDeferredMessage *oldMessage,
+ BusDeferredMessage *newMessage)
+{
+ DBusList *link;
+ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+
+ link = _dbus_list_find_first(&d->deferred_messages, oldMessage);
+ if (link == NULL)
+ return FALSE;
+
+ if (!_dbus_list_insert_after(&d->deferred_messages, link, newMessage))
+ return FALSE;
+
+ bus_deferred_message_ref(newMessage);
+ _dbus_list_remove_link(&d->deferred_messages, link);
+ bus_deferred_message_unref(oldMessage);
+ return TRUE;
+}
+
+BusDeferredMessage *
+bus_connection_pop_deferred_message (DBusConnection *connection)
+{
+ DBusList *link;
+ BusDeferredMessage *message;
+ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+
+ link =_dbus_list_get_first_link(&d->deferred_messages);
+ if (link != NULL)
+ {
+ message = link->data;
+ if (!bus_deferred_message_waits_for_check(message))
+ {
+ _dbus_list_remove_link(&d->deferred_messages, link);
+ return message;
+ }
+ }
+
+ return NULL;
+}
+
+dbus_bool_t
+bus_connection_putback_deferred_message (DBusConnection *connection, BusDeferredMessage *message)
+{
+ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+ if (_dbus_list_prepend(&d->deferred_messages, message))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+bus_connection_clear_deferred_messages (DBusConnection *connection)
+{
+ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+ DBusList *link;
+ DBusList *next;
+ BusDeferredMessage *message;
+
+ link =_dbus_list_get_first_link(&d->deferred_messages);
+ while (link != NULL)
+ {
+ next = _dbus_list_get_next_link (&d->deferred_messages, link);
+ message = link->data;
+
+ bus_deferred_message_unref(message);
+ _dbus_list_remove_link(&d->deferred_messages, link);
+
+ link = next;
+ }
+}
+
+void
+bus_connection_remove_deferred_message (DBusConnection *connection,
+ BusDeferredMessage *message)
+{
+ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+ if (_dbus_list_remove(&d->deferred_messages, message))
+ bus_deferred_message_unref(message);
+}
+
int
bus_connections_get_n_active (BusConnections *connections)
{
void bus_connection_send_oom_error (DBusConnection *connection,
DBusMessage *in_reply_to);
+dbus_bool_t bus_connection_has_deferred_messages (DBusConnection *connection);
+dbus_bool_t bus_connection_queue_deferred_message (DBusConnection *connection,
+ BusDeferredMessage *message,
+ dbus_bool_t prepend);
+BusDeferredMessage *bus_connection_pop_deferred_message (DBusConnection *connection);
+dbus_bool_t bus_connection_putback_deferred_message (DBusConnection *connection,
+ BusDeferredMessage *message);
+void bus_connection_remove_deferred_message (DBusConnection *connection,
+ BusDeferredMessage *message);
+dbus_bool_t bus_connection_replace_deferred_message (DBusConnection *connection,
+ BusDeferredMessage *oldMessage,
+ BusDeferredMessage *newMessage);
+void bus_connection_dispatch_deferred (DBusConnection *connection);
+void bus_connection_clear_deferred_messages (DBusConnection *connection);
+
+
/* called by signals.c */
dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection,
BusMatchRule *rule);
BusContext* bus_transaction_get_context (BusTransaction *transaction);
dbus_bool_t bus_transaction_send (BusTransaction *transaction,
DBusConnection *connection,
- DBusMessage *message);
+ DBusMessage *message,
+ dbus_bool_t deferred_dispatch);
dbus_bool_t bus_transaction_capture (BusTransaction *transaction,
DBusConnection *connection,
DBusMessage *message);
#include "utils.h"
#include "bus.h"
#include "signals.h"
+#include "dispatch.h"
#include "test.h"
#include <dbus/dbus-internals.h>
+#include <dbus/dbus-connection-internal.h>
#include <dbus/dbus-misc.h>
#include <string.h>
result = bus_context_check_security_policy (context, transaction, sender, addressed_recipient,
connection, message, NULL, &deferred_message);
- if (result != BUS_RESULT_TRUE)
+ if (result == BUS_RESULT_FALSE)
{
if (!bus_transaction_capture_error_reply (transaction, &stack_error,
message))
return TRUE; /* don't send it but don't return an error either */
}
+ if (result == BUS_RESULT_LATER)
+ {
+ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+ return TRUE; /* pretend to have sent it */
+ }
+
if (!bus_transaction_send (transaction,
connection,
- message))
+ message, FALSE))
{
BUS_SET_OOM (error);
return FALSE;
}
BusResult
-bus_dispatch_matches (BusTransaction *transaction,
- DBusConnection *sender,
- DBusConnection *addressed_recipient,
- DBusMessage *message,
- DBusError *error)
+bus_dispatch_matches (BusTransaction *transaction,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusMessage *message,
+ BusDeferredMessage *dispatched_deferred_message,
+ DBusError *error)
{
DBusError tmp_error;
BusConnections *connections;
/* First, send the message to the addressed_recipient, if there is one. */
if (addressed_recipient != NULL)
{
- switch (bus_context_check_security_policy (context, transaction,
- sender, addressed_recipient,
- addressed_recipient,
- message, error,
- &deferred_message))
+ BusResult result;
+ /* To maintain message order message needs to be appended at the recipient if there are already
+ * deferred messages and we are not doing deferred dispatch
+ */
+ if (dispatched_deferred_message == NULL && bus_connection_has_deferred_messages(addressed_recipient))
{
- case BUS_RESULT_TRUE:
- break;
- case BUS_RESULT_FALSE:
- return BUS_RESULT_FALSE;
- case BUS_RESULT_LATER:
+ deferred_message = bus_deferred_message_new(message, sender,
+ addressed_recipient, addressed_recipient, BUS_RESULT_LATER);
+
+ if (deferred_message == NULL)
{
- BusDeferredMessageStatus status;
- status = bus_deferred_message_get_status(deferred_message);
+ BUS_SET_OOM(error);
+ return BUS_RESULT_FALSE;
+ }
- if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
- {
- /* send rule result not available - disable dispatching messages from the sender */
- bus_deferred_message_disable_sender(deferred_message);
- return BUS_RESULT_LATER;
- }
- else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
- {
- dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
- "Rejecting message because time is needed to check security policy");
- return BUS_RESULT_FALSE;
- }
- else
- {
- _dbus_verbose("deferred message has no status field set to send or receive unexpectedly\n");
- return BUS_RESULT_FALSE;
- }
+ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
+ {
+ bus_deferred_message_unref(deferred_message);
+ BUS_SET_OOM(error);
+ return BUS_RESULT_FALSE;
+ }
+
+ bus_deferred_message_unref(deferred_message);
+ return BUS_RESULT_TRUE; /* pretend to have sent it */
+ }
+
+ if (dispatched_deferred_message != NULL)
+ {
+ result = bus_deferred_message_get_response(dispatched_deferred_message);
+ if (result == BUS_RESULT_TRUE)
+ {
+ /* if we know the result of policy check we still need to check if message limits
+ * are not exceeded. It is also required to add entry in expected replies list if
+ * this is a method call
+ */
+ if (!bus_deferred_message_check_message_limits(dispatched_deferred_message, error))
+ return BUS_RESULT_FALSE;
+
+ if (!bus_deferred_message_expect_method_reply(dispatched_deferred_message, transaction, error))
+ return BUS_RESULT_FALSE;
+ }
+ else if (result == BUS_RESULT_FALSE)
+ {
+ bus_deferred_message_create_error(dispatched_deferred_message, "Rejected message", error);
+ return BUS_RESULT_FALSE;
+ }
+ }
+ else
+ result = BUS_RESULT_LATER;
+
+ if (result == BUS_RESULT_LATER)
+ result = bus_context_check_security_policy(context, transaction,
+ sender, addressed_recipient, addressed_recipient, message, error,
+ &deferred_message);
+
+ switch (result)
+ {
+ case BUS_RESULT_TRUE:
+ break;
+ case BUS_RESULT_FALSE:
+ return BUS_RESULT_FALSE;
+ case BUS_RESULT_LATER:
+ {
+ BusDeferredMessageStatus status;
+
+ if (dispatched_deferred_message != NULL)
+ {
+ /* for deferred dispatch prepend message at the recipient */
+ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, TRUE))
+ {
+ BUS_SET_OOM(error);
+ return BUS_RESULT_FALSE;
+ }
+ return BUS_RESULT_TRUE; /* pretend to have sent it */
+ }
+
+ status = bus_deferred_message_get_status(deferred_message);
+
+ if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
+ {
+ /* send rule result not available - disable dispatching messages from the sender */
+ bus_deferred_message_disable_sender(deferred_message);
+ return BUS_RESULT_LATER;
+ }
+ else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
+ {
+ /* receive rule result not available - queue message at the recipient */
+ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
+ {
+ BUS_SET_OOM(error);
+ return BUS_RESULT_FALSE;
+ }
+
+ return BUS_RESULT_TRUE; /* pretend to have sent it */
+ }
+ else
+ {
+ _dbus_verbose("deferred message has no status field set unexpectedly\n");
+ return BUS_RESULT_FALSE;
}
+ }
}
if (dbus_message_contains_unix_fds (message) &&
}
/* Dispatch the message */
- if (!bus_transaction_send (transaction, addressed_recipient, message))
+ if (!bus_transaction_send(transaction, addressed_recipient, message,
+ dispatched_deferred_message != NULL ? TRUE : FALSE))
{
BUS_SET_OOM (error);
return BUS_RESULT_FALSE;
* addressed_recipient == NULL), and match it against other connections'
* match rules.
*/
- switch (bus_dispatch_matches (transaction, connection, addressed_recipient, message, &error))
+ switch (bus_dispatch_matches (transaction, connection, addressed_recipient, message, NULL, &error))
{
case BUS_RESULT_TRUE:
case BUS_RESULT_FALSE:
dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection);
void bus_dispatch_remove_connection (DBusConnection *connection);
-BusResult bus_dispatch_matches (BusTransaction *transaction,
- DBusConnection *sender,
- DBusConnection *recipient,
- DBusMessage *message,
- DBusError *error);
+BusResult bus_dispatch_matches (BusTransaction *transaction,
+ DBusConnection *sender,
+ DBusConnection *recipient,
+ DBusMessage *message,
+ BusDeferredMessage *dispatched_deferred_message,
+ DBusError *error);
#endif /* BUS_DISPATCH_H */
if (!bus_transaction_capture (transaction, NULL, message))
goto oom;
- switch (bus_dispatch_matches (transaction, NULL, NULL, message, error))
+ switch (bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error))
{
case BUS_RESULT_TRUE:
retval = TRUE;
result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
+ if (result == BUS_RESULT_LATER && deferred_message != NULL)
+ bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
+ *toggles, privilege);
}
else
privilege = NULL;
result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
+ if (result == BUS_RESULT_LATER && deferred_message != NULL)
+ bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
+ *toggles, privilege);
}
else
privilege = NULL;