1 From 1e231194610892dd4360224998d91336097b05a1 Mon Sep 17 00:00:00 2001
2 From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
3 Date: Fri, 28 Nov 2014 12:39:33 +0100
4 Subject: [PATCH 6/8] Handle unavailability of policy results for broadcasts
7 When message is sent to the addressed recipient and receive rule
8 result is unavailable we don't want to block the sender
9 as it most likely will be the privileged service, so instead we queue
10 it at the recipient. Any further messages sent to it will be queued to
11 maintain message order. Once the answer from Cynara arrives messages are
12 dispatched from the recipient queue. In such case full dispatch is
13 performed - messages are sent to addressed recipient and other
14 interested connections.
15 Messages sent to non-addressed recipients (eavesdroppers or broadcast
16 message recipients) are handled in a similar way. The difference is
17 that it is not full dispatch meaning message is sent to a single recipient.
19 Change-Id: Iecd5395f75a4c7811fa97247a37d8fc4d42e8814
21 bus/activation.c | 4 +-
22 bus/bus.c | 50 +++++++--
24 bus/check.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
25 bus/check.h | 25 +++++
26 bus/connection.c | 166 ++++++++++++++++++++++++++++--
27 bus/connection.h | 19 +++-
28 bus/dispatch.c | 122 ++++++++++++++++++----
29 bus/dispatch.h | 11 +-
32 11 files changed, 685 insertions(+), 46 deletions(-)
34 diff --git a/bus/activation.c b/bus/activation.c
35 index 8c43941..308bf41 100644
36 --- a/bus/activation.c
37 +++ b/bus/activation.c
38 @@ -1198,7 +1198,7 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation
39 res = bus_dispatch_matches (transaction,
42 - entry->activation_message, &error);
43 + entry->activation_message, NULL, &error);
44 if (res == BUS_RESULT_FALSE)
46 /* If permission is denied, we just want to return the error
47 @@ -2066,7 +2066,7 @@ bus_activation_activate_service (BusActivation *activation,
48 entry->systemd_service);
49 /* Wonderful, systemd is connected, let's just send the msg */
50 res = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service),
52 + message, NULL, error);
54 if (res == BUS_RESULT_TRUE)
56 diff --git a/bus/bus.c b/bus/bus.c
57 index ac9ea8d..b478b8e 100644
60 @@ -1704,17 +1704,9 @@ bus_context_check_security_policy (BusContext *context,
63 /* See if limits on size have been exceeded */
64 - if (proposed_recipient &&
65 - ((dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) ||
66 - (dbus_connection_get_outgoing_unix_fds (proposed_recipient) > context->limits.max_outgoing_unix_fds)))
68 - complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
69 - "Rejected: destination has a full message queue",
70 - 0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
72 - _dbus_verbose ("security policy disallowing message due to full message queue\n");
73 + if (!bus_context_check_recipient_message_limits(context, proposed_recipient, sender, message,
74 + requested_reply, error))
75 return BUS_RESULT_FALSE;
78 /* Record that we will allow a reply here in the future (don't
79 * bother if the recipient is the bus or this is an eavesdropping
80 @@ -1769,3 +1761,41 @@ bus_context_check_all_watches (BusContext *context)
81 _dbus_server_toggle_all_watches (server, enabled);
86 +bus_context_complain_about_message (BusContext *context,
87 + const char *error_name,
88 + const char *complaint,
90 + DBusMessage *message,
91 + DBusConnection *sender,
92 + DBusConnection *proposed_recipient,
93 + dbus_bool_t requested_reply,
95 + const char *privilege,
98 + complain_about_message(context, error_name, complaint, matched_rules, message, sender,
99 + proposed_recipient, requested_reply, log, privilege, error);
102 +dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
103 + DBusConnection *recipient,
104 + DBusConnection *sender,
105 + DBusMessage *message,
106 + dbus_bool_t requested_reply,
110 + ((dbus_connection_get_outgoing_size (recipient) > context->limits.max_outgoing_bytes) ||
111 + (dbus_connection_get_outgoing_unix_fds (recipient) > context->limits.max_outgoing_unix_fds)))
113 + complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
114 + "Rejected: destination has a full message queue",
115 + 0, message, sender, recipient, requested_reply, TRUE, NULL,
117 + _dbus_verbose ("security policy disallowing message due to full message queue\n");
122 diff --git a/bus/bus.h b/bus/bus.h
123 index 78084dd..27a5e49 100644
126 @@ -148,4 +148,23 @@ BusResult bus_context_check_security_policy (BusContext
128 BusDeferredMessage **deferred_message);
130 +dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
131 + DBusConnection *recipient,
132 + DBusConnection *sender,
133 + DBusMessage *message,
134 + dbus_bool_t requested_reply,
136 +void bus_context_complain_about_message (BusContext *context,
137 + const char *error_name,
138 + const char *complaint,
140 + DBusMessage *message,
141 + DBusConnection *sender,
142 + DBusConnection *proposed_recipient,
143 + dbus_bool_t requested_reply,
145 + const char *privilege,
149 #endif /* BUS_BUS_H */
150 diff --git a/bus/check.c b/bus/check.c
151 index cd6a74b..733763a 100644
154 @@ -49,6 +49,9 @@ typedef struct BusDeferredMessage
155 DBusConnection *sender;
156 DBusConnection *proposed_recipient;
157 DBusConnection *addressed_recipient;
158 + dbus_bool_t requested_reply;
160 + const char *privilege;
161 dbus_bool_t full_dispatch;
162 BusDeferredMessageStatus status;
164 @@ -136,6 +139,89 @@ bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
168 +bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
173 + _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
175 + if (!bus_connection_is_active(deferred_message->proposed_recipient))
178 + status = deferred_message->status;
180 + deferred_message->status = 0; /* mark message as not waiting for response */
181 + deferred_message->response = result;
184 + * If send rule allows us to send message we still need to check receive rules.
186 + if ((status & BUS_DEFERRED_MESSAGE_CHECK_SEND) && (result == BUS_RESULT_TRUE))
189 + BusContext *context;
190 + BusRegistry *registry;
191 + BusClientPolicy *recipient_policy;
192 + BusDeferredMessage *deferred_message_receive;
194 + context = bus_connection_get_context(deferred_message->proposed_recipient);
195 + registry = bus_context_get_registry(context);
196 + recipient_policy = bus_connection_get_policy(deferred_message->proposed_recipient);
198 + deferred_message->response = bus_client_policy_check_can_receive(recipient_policy, registry,
199 + deferred_message->requested_reply, deferred_message->sender,
200 + deferred_message->addressed_recipient, deferred_message->proposed_recipient, deferred_message->message,
201 + &toggles, NULL, &deferred_message_receive);
202 + if (deferred_message->response == BUS_RESULT_LATER)
204 + /* replace deferred message associated with send check with the one associated with
206 + if (!bus_deferred_message_replace(deferred_message, deferred_message_receive))
208 + /* failed to replace deferred message (due to oom). Set it to rejected */
209 + deferred_message->response = BUS_RESULT_FALSE;
214 + bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
218 +queue_deferred_message_cancel_transaction_hook (void *data)
220 + BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
221 + bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
226 +bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
227 + BusTransaction *transaction,
228 + dbus_bool_t full_dispatch,
229 + dbus_bool_t prepend)
231 + _dbus_assert(deferred_message != NULL);
232 + _dbus_assert(deferred_message->proposed_recipient != NULL);
234 + if (!bus_connection_queue_deferred_message(deferred_message->proposed_recipient,
235 + deferred_message, prepend))
238 + if (!bus_transaction_add_cancel_hook(transaction, queue_deferred_message_cancel_transaction_hook,
239 + deferred_message, NULL))
241 + bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
244 + deferred_message->response_callback = bus_check_queued_message_reply_callback;
245 + deferred_message->full_dispatch = full_dispatch;
251 deferred_message_free_function(void *data)
253 BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
254 @@ -159,6 +245,20 @@ bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
255 deferred_message->response_callback = bus_check_enable_dispatch_callback;
259 +bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
260 + dbus_bool_t requested_reply,
262 + const char *privilege)
264 + _dbus_assert(deferred_message != NULL);
266 + deferred_message->requested_reply = requested_reply;
267 + deferred_message->matched_rules = matched_rules;
268 + deferred_message->privilege = privilege;
272 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
273 dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
274 const char *privilege);
275 @@ -257,6 +357,9 @@ BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
276 deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
277 deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
278 deferred_message->message = dbus_message_ref(message);
279 + deferred_message->requested_reply = FALSE;
280 + deferred_message->matched_rules = 0;
281 + deferred_message->privilege = NULL;
282 deferred_message->response = response;
283 deferred_message->status = 0;
284 deferred_message->full_dispatch = FALSE;
285 @@ -293,12 +396,215 @@ bus_deferred_message_unref (BusDeferredMessage *deferred_message)
290 +bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message, DBusError *error)
292 + BusContext *context = bus_connection_get_context(deferred_message->proposed_recipient);
294 + return bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
295 + deferred_message->sender, deferred_message->message, deferred_message->requested_reply,
300 +bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, BusTransaction *transaction, DBusError *error)
302 + int type = dbus_message_get_type(deferred_message->message);
303 + if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
304 + deferred_message->sender &&
305 + deferred_message->addressed_recipient &&
306 + deferred_message->addressed_recipient == deferred_message->proposed_recipient && /* not eavesdropping */
307 + !bus_connections_expect_reply (bus_connection_get_connections (deferred_message->sender),
309 + deferred_message->sender, deferred_message->addressed_recipient,
310 + deferred_message->message, error))
312 + _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
319 +bus_deferred_message_create_error(BusDeferredMessage *deferred_message,
320 + const char *error_message, DBusError *error)
322 + BusContext *context;
323 + _dbus_assert (deferred_message->status == 0 && deferred_message->response == BUS_RESULT_FALSE);
325 + if (deferred_message->sender == NULL)
326 + return; /* error won't be sent to bus driver anyway */
328 + context = bus_connection_get_context(deferred_message->sender);
329 + bus_context_complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected message",
330 + deferred_message->matched_rules, deferred_message->message, deferred_message->sender,
331 + deferred_message->proposed_recipient, deferred_message->requested_reply, FALSE,
332 + deferred_message->privilege, error);
336 +bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
338 + BusContext *context = bus_connection_get_context (deferred_message->proposed_recipient);
339 + BusTransaction *transaction = bus_transaction_new (context);
340 + BusResult result = BUS_RESULT_TRUE;
343 + if (transaction == NULL)
345 + return BUS_RESULT_FALSE;
348 + dbus_error_init(&error);
350 + if (!deferred_message->full_dispatch)
352 + result = deferred_message->response;
353 + if (result == BUS_RESULT_TRUE)
355 + if (!bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
356 + deferred_message->sender, deferred_message->message, deferred_message->requested_reply, &error))
357 + result = BUS_RESULT_FALSE;
359 + else if (result == BUS_RESULT_LATER)
361 + BusDeferredMessage *deferred_message2;
362 + result = bus_context_check_security_policy (context, transaction,
363 + deferred_message->sender,
364 + deferred_message->addressed_recipient,
365 + deferred_message->proposed_recipient,
366 + deferred_message->message, NULL,
367 + &deferred_message2);
369 + if (result == BUS_RESULT_LATER)
371 + /* prepend at recipient */
372 + if (!bus_deferred_message_queue_at_recipient(deferred_message2, transaction,
374 + result = BUS_RESULT_FALSE;
378 + /* silently drop messages on access denial */
379 + if (result == BUS_RESULT_TRUE)
381 + if (!bus_transaction_send (transaction, deferred_message->proposed_recipient, deferred_message->message, TRUE))
382 + result = BUS_RESULT_FALSE;
385 + bus_transaction_execute_and_free(transaction);
390 + /* do not attempt to send message if sender has disconnected */
391 + if (deferred_message->sender != NULL && !bus_connection_is_active(deferred_message->sender))
393 + bus_transaction_cancel_and_free(transaction);
394 + result = BUS_RESULT_FALSE;
398 + result = bus_dispatch_matches(transaction, deferred_message->sender,
399 + deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
401 + if (result == BUS_RESULT_LATER)
403 + /* Message deferring was already done in bus_dispatch_matches */
404 + bus_transaction_cancel_and_free(transaction);
408 + /* this part is a copy & paste from bus_dispatch function. Probably can be moved to a function */
409 + if (dbus_error_is_set (&error))
411 + if (!dbus_connection_get_is_connected (deferred_message->sender))
413 + /* If we disconnected it, we won't bother to send it any error
416 + _dbus_verbose ("Not sending error to connection we disconnected\n");
418 + else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
420 + bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
422 + /* cancel transaction due to OOM */
423 + if (transaction != NULL)
425 + bus_transaction_cancel_and_free (transaction);
426 + transaction = NULL;
431 + /* Try to send the real error, if no mem to do that, send
434 + _dbus_assert (transaction != NULL);
435 + if (!bus_transaction_send_error_reply (transaction, deferred_message->sender,
436 + &error, deferred_message->message))
438 + bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
440 + /* cancel transaction due to OOM */
441 + if (transaction != NULL)
443 + bus_transaction_cancel_and_free (transaction);
444 + transaction = NULL;
450 + if (transaction != NULL)
452 + bus_transaction_execute_and_free (transaction);
456 + dbus_error_free(&error);
462 +bus_deferred_message_replace (BusDeferredMessage *old_message, BusDeferredMessage *new_message)
464 + if (bus_connection_replace_deferred_message(old_message->proposed_recipient,
465 + old_message, new_message))
467 + new_message->response_callback = old_message->response_callback;
468 + new_message->full_dispatch = old_message->full_dispatch;
475 +bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
477 + return deferred_message->status != 0;
481 +bus_deferred_message_get_recipient(BusDeferredMessage *deferred_message)
483 + return deferred_message->proposed_recipient;
486 BusDeferredMessageStatus
487 bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
489 return deferred_message->status;
493 +bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
495 + return deferred_message->response;
499 bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
501 @@ -308,3 +614,4 @@ bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
502 deferred_message->response_callback(deferred_message, result);
506 diff --git a/bus/check.h b/bus/check.h
507 index f381789..3c6b2a1 100644
510 @@ -64,12 +64,37 @@ BusDeferredMessage *bus_deferred_message_new (DBusMessage *messag
512 BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message);
513 void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
514 +BusResult bus_deferred_message_dispatch (BusDeferredMessage *deferred_message);
515 +dbus_bool_t bus_deferred_message_waits_for_check (BusDeferredMessage *deferred_message);
516 +DBusConnection *bus_deferred_message_get_recipient (BusDeferredMessage *deferred_message);
517 void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
519 +dbus_bool_t bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
520 + BusTransaction *transaction,
521 + dbus_bool_t full_dispatch,
522 + dbus_bool_t prepend);
523 +dbus_bool_t bus_deferred_message_replace (BusDeferredMessage *old_message,
524 + BusDeferredMessage *new_message);
525 void bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message);
526 +BusResult bus_deferred_message_get_response (BusDeferredMessage *deferred_message);
528 BusDeferredMessageStatus bus_deferred_message_get_status (BusDeferredMessage *deferred_message);
531 +dbus_bool_t bus_deferred_message_expect_method_reply (BusDeferredMessage *deferred_message,
532 + BusTransaction *transaction,
534 +void bus_deferred_message_create_error (BusDeferredMessage *deferred_message,
535 + const char *error_message,
537 +void bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
538 + dbus_bool_t requested_reply,
540 + const char *privilege);
541 +dbus_bool_t bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message,
545 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
546 extern dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
547 const char *privilege);
548 diff --git a/bus/connection.c b/bus/connection.c
549 index a6d87e5..d2ebe82 100644
550 --- a/bus/connection.c
551 +++ b/bus/connection.c
554 #include "expirelist.h"
557 #include <dbus/dbus-list.h>
558 #include <dbus/dbus-hash.h>
559 #include <dbus/dbus-timeout.h>
560 #include <dbus/dbus-connection-internal.h>
561 +#include <dbus/dbus-message-internal.h>
562 #ifdef DBUS_ENABLE_CYNARA
564 #include <cynara-session.h>
565 @@ -95,6 +97,7 @@ typedef struct
566 DBusMessage *oom_message;
567 DBusPreallocatedSend *oom_preallocated;
568 BusClientPolicy *policy;
569 + DBusList *deferred_messages; /**< Queue of messages deferred due to pending policy check */
571 char *cached_loginfo_string;
572 BusSELinuxID *selinux_id;
573 @@ -256,6 +259,8 @@ bus_connection_disconnected (DBusConnection *connection)
574 bus_transaction_execute_and_free (transaction);
577 + bus_connection_clear_deferred_messages(connection);
579 bus_dispatch_remove_connection (connection);
581 /* no more watching */
582 @@ -2132,6 +2137,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
583 DBusMessage *message)
586 + BusDeferredMessage *deferred_message;
587 /* We have to set the sender to the driver, and have
588 * to check security policy since it was not done in
590 @@ -2163,23 +2169,25 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
591 res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
593 NULL, connection, connection, message, NULL,
595 + &deferred_message);
597 if (res == BUS_RESULT_FALSE)
599 else if (res == BUS_RESULT_LATER)
601 - _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
603 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
605 + return TRUE; /* pretend to have sent it */
608 - return bus_transaction_send (transaction, connection, message);
609 + return bus_transaction_send (transaction, connection, message, FALSE);
613 bus_transaction_send (BusTransaction *transaction,
614 DBusConnection *connection,
615 - DBusMessage *message)
616 + DBusMessage *message,
617 + dbus_bool_t deferred_dispatch)
619 MessageToSend *to_send;
620 BusConnectionData *d;
621 @@ -2205,7 +2213,28 @@ bus_transaction_send (BusTransaction *transaction,
623 d = BUS_CONNECTION_DATA (connection);
624 _dbus_assert (d != NULL);
627 + if (!deferred_dispatch && d->deferred_messages != NULL)
629 + BusDeferredMessage *deferred_message;
630 + dbus_bool_t success;
631 + /* sender and addressed recipient are not required at this point as we only need to send message
632 + * to a single recipient without performing policy check. */
633 + deferred_message = bus_deferred_message_new (message,
638 + if (deferred_message == NULL)
641 + success = bus_deferred_message_queue_at_recipient(deferred_message, transaction,
643 + bus_deferred_message_unref(deferred_message);
648 to_send = dbus_new (MessageToSend, 1);
651 @@ -2457,6 +2486,131 @@ bus_transaction_add_cancel_hook (BusTransaction *transaction,
656 +bus_connection_dispatch_deferred (DBusConnection *connection)
658 + BusDeferredMessage *message;
660 + _dbus_return_if_fail (connection != NULL);
662 + while ((message = bus_connection_pop_deferred_message(connection)) != NULL)
664 + bus_deferred_message_dispatch(message);
665 + bus_deferred_message_unref(message);
670 +bus_connection_has_deferred_messages (DBusConnection *connection)
672 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
673 + return d->deferred_messages != NULL ? TRUE : FALSE;
677 +bus_connection_queue_deferred_message (DBusConnection *connection,
678 + BusDeferredMessage *message,
679 + dbus_bool_t prepend)
681 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
682 + dbus_bool_t success;
684 + success = _dbus_list_prepend(&d->deferred_messages, message);
686 + success = _dbus_list_append(&d->deferred_messages, message);
690 + bus_deferred_message_ref(message);
698 +bus_connection_replace_deferred_message (DBusConnection *connection,
699 + BusDeferredMessage *oldMessage,
700 + BusDeferredMessage *newMessage)
703 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
705 + link = _dbus_list_find_first(&d->deferred_messages, oldMessage);
709 + if (!_dbus_list_insert_after(&d->deferred_messages, link, newMessage))
712 + bus_deferred_message_ref(newMessage);
713 + _dbus_list_remove_link(&d->deferred_messages, link);
714 + bus_deferred_message_unref(oldMessage);
718 +BusDeferredMessage *
719 +bus_connection_pop_deferred_message (DBusConnection *connection)
722 + BusDeferredMessage *message;
723 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
725 + link =_dbus_list_get_first_link(&d->deferred_messages);
728 + message = link->data;
729 + if (!bus_deferred_message_waits_for_check(message))
731 + _dbus_list_remove_link(&d->deferred_messages, link);
740 +bus_connection_putback_deferred_message (DBusConnection *connection, BusDeferredMessage *message)
742 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
743 + if (_dbus_list_prepend(&d->deferred_messages, message))
751 +bus_connection_clear_deferred_messages (DBusConnection *connection)
753 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
756 + BusDeferredMessage *message;
758 + link =_dbus_list_get_first_link(&d->deferred_messages);
759 + while (link != NULL)
761 + next = _dbus_list_get_next_link (&d->deferred_messages, link);
762 + message = link->data;
764 + bus_deferred_message_unref(message);
765 + _dbus_list_remove_link(&d->deferred_messages, link);
772 +bus_connection_remove_deferred_message (DBusConnection *connection,
773 + BusDeferredMessage *message)
775 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
776 + if (_dbus_list_remove(&d->deferred_messages, message))
777 + bus_deferred_message_unref(message);
781 bus_connections_get_n_active (BusConnections *connections)
783 diff --git a/bus/connection.h b/bus/connection.h
784 index 7433746..8d49b25 100644
785 --- a/bus/connection.h
786 +++ b/bus/connection.h
787 @@ -82,6 +82,22 @@ dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection);
788 void bus_connection_send_oom_error (DBusConnection *connection,
789 DBusMessage *in_reply_to);
791 +dbus_bool_t bus_connection_has_deferred_messages (DBusConnection *connection);
792 +dbus_bool_t bus_connection_queue_deferred_message (DBusConnection *connection,
793 + BusDeferredMessage *message,
794 + dbus_bool_t prepend);
795 +BusDeferredMessage *bus_connection_pop_deferred_message (DBusConnection *connection);
796 +dbus_bool_t bus_connection_putback_deferred_message (DBusConnection *connection,
797 + BusDeferredMessage *message);
798 +void bus_connection_remove_deferred_message (DBusConnection *connection,
799 + BusDeferredMessage *message);
800 +dbus_bool_t bus_connection_replace_deferred_message (DBusConnection *connection,
801 + BusDeferredMessage *oldMessage,
802 + BusDeferredMessage *newMessage);
803 +void bus_connection_dispatch_deferred (DBusConnection *connection);
804 +void bus_connection_clear_deferred_messages (DBusConnection *connection);
807 /* called by signals.c */
808 dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection,
810 @@ -129,7 +145,8 @@ BusTransaction* bus_transaction_new (BusContext *
811 BusContext* bus_transaction_get_context (BusTransaction *transaction);
812 dbus_bool_t bus_transaction_send (BusTransaction *transaction,
813 DBusConnection *connection,
814 - DBusMessage *message);
815 + DBusMessage *message,
816 + dbus_bool_t deferred_dispatch);
817 dbus_bool_t bus_transaction_send_from_driver (BusTransaction *transaction,
818 DBusConnection *connection,
819 DBusMessage *message);
820 diff --git a/bus/dispatch.c b/bus/dispatch.c
821 index 6b0eadc..9972e76 100644
828 +#include "dispatch.h"
830 #include <dbus/dbus-internals.h>
831 +#include <dbus/dbus-connection-internal.h>
832 #include <dbus/dbus-misc.h>
835 @@ -63,16 +65,26 @@ send_one_message (DBusConnection *connection,
836 result = bus_context_check_security_policy (context, transaction, sender, addressed_recipient,
837 connection, message, NULL, &deferred_message);
839 - if (result != BUS_RESULT_TRUE)
840 + if (result == BUS_RESULT_FALSE)
841 return TRUE; /* silently don't send it */
843 if (dbus_message_contains_unix_fds(message) &&
844 !dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD))
845 return TRUE; /* silently don't send it */
847 + if (result == BUS_RESULT_LATER)
849 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
851 + BUS_SET_OOM (error);
854 + return TRUE; /* pretend to have sent it */
857 if (!bus_transaction_send (transaction,
864 @@ -82,11 +94,12 @@ send_one_message (DBusConnection *connection,
868 -bus_dispatch_matches (BusTransaction *transaction,
869 - DBusConnection *sender,
870 - DBusConnection *addressed_recipient,
871 - DBusMessage *message,
873 +bus_dispatch_matches (BusTransaction *transaction,
874 + DBusConnection *sender,
875 + DBusConnection *addressed_recipient,
876 + DBusMessage *message,
877 + BusDeferredMessage *dispatched_deferred_message,
881 BusConnections *connections;
882 @@ -110,17 +123,78 @@ bus_dispatch_matches (BusTransaction *transaction,
883 /* First, send the message to the addressed_recipient, if there is one. */
884 if (addressed_recipient != NULL)
887 - res = bus_context_check_security_policy (context, transaction,
888 - sender, addressed_recipient,
889 - addressed_recipient,
891 - &deferred_message);
892 - if (res == BUS_RESULT_FALSE)
894 + /* To maintain message order message needs to be appended at the recipient if there are already
895 + * deferred messages and we are not doing deferred dispatch
897 + if (dispatched_deferred_message == NULL && bus_connection_has_deferred_messages(addressed_recipient))
899 + deferred_message = bus_deferred_message_new(message, sender,
900 + addressed_recipient, addressed_recipient, BUS_RESULT_LATER);
902 + if (deferred_message == NULL)
904 + BUS_SET_OOM(error);
905 + return BUS_RESULT_FALSE;
908 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
910 + bus_deferred_message_unref(deferred_message);
911 + BUS_SET_OOM(error);
912 + return BUS_RESULT_FALSE;
915 + bus_deferred_message_unref(deferred_message);
916 + return BUS_RESULT_TRUE; /* pretend to have sent it */
919 + if (dispatched_deferred_message != NULL)
921 + result = bus_deferred_message_get_response(dispatched_deferred_message);
922 + if (result == BUS_RESULT_TRUE)
924 + /* if we know the result of policy check we still need to check if message limits
925 + * are not exceeded. It is also required to add entry in expected replies list if
926 + * this is a method call
928 + if (!bus_deferred_message_check_message_limits(dispatched_deferred_message, error))
929 + return BUS_RESULT_FALSE;
931 + if (!bus_deferred_message_expect_method_reply(dispatched_deferred_message, transaction, error))
932 + return BUS_RESULT_FALSE;
934 + else if (result == BUS_RESULT_FALSE)
936 + bus_deferred_message_create_error(dispatched_deferred_message, "Rejected message", error);
937 + return BUS_RESULT_FALSE;
941 + result = BUS_RESULT_LATER;
943 + if (result == BUS_RESULT_LATER)
944 + result = bus_context_check_security_policy(context, transaction,
945 + sender, addressed_recipient, addressed_recipient, message, error,
946 + &deferred_message);
948 + if (result == BUS_RESULT_FALSE)
949 return BUS_RESULT_FALSE;
950 - else if (res == BUS_RESULT_LATER)
951 + else if (result == BUS_RESULT_LATER)
953 BusDeferredMessageStatus status;
955 + if (dispatched_deferred_message != NULL)
957 + /* for deferred dispatch prepend message at the recipient */
958 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, TRUE))
960 + BUS_SET_OOM(error);
961 + return BUS_RESULT_FALSE;
963 + return BUS_RESULT_TRUE; /* pretend to have sent it */
966 status = bus_deferred_message_get_status(deferred_message);
968 if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
969 @@ -131,13 +205,18 @@ bus_dispatch_matches (BusTransaction *transaction,
971 else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
973 - dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
974 - "Rejecting message because time is needed to check security policy");
975 - return BUS_RESULT_FALSE;
976 + /* receive rule result not available - queue message at the recipient */
977 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
979 + BUS_SET_OOM(error);
980 + return BUS_RESULT_FALSE;
983 + return BUS_RESULT_TRUE; /* pretend to have sent it */
987 - _dbus_verbose("deferred message has no status field set to send or receive unexpectedly\n");
988 + _dbus_verbose("deferred message has no status field set unexpectedly\n");
989 return BUS_RESULT_FALSE;
992 @@ -154,7 +233,8 @@ bus_dispatch_matches (BusTransaction *transaction,
995 /* Dispatch the message */
996 - if (!bus_transaction_send (transaction, addressed_recipient, message))
997 + if (!bus_transaction_send(transaction, addressed_recipient, message,
998 + dispatched_deferred_message != NULL ? TRUE : FALSE))
1000 BUS_SET_OOM (error);
1001 return BUS_RESULT_FALSE;
1002 @@ -385,7 +465,7 @@ bus_dispatch (DBusConnection *connection,
1005 if (BUS_RESULT_LATER == bus_dispatch_matches (transaction, connection, addressed_recipient,
1007 + message, NULL, &error))
1009 /* Roll back and dispatch the message once the policy result is available */
1010 bus_transaction_cancel_and_free (transaction);
1011 diff --git a/bus/dispatch.h b/bus/dispatch.h
1012 index afba6a2..f6102e8 100644
1013 --- a/bus/dispatch.h
1014 +++ b/bus/dispatch.h
1017 dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection);
1018 void bus_dispatch_remove_connection (DBusConnection *connection);
1019 -BusResult bus_dispatch_matches (BusTransaction *transaction,
1020 - DBusConnection *sender,
1021 - DBusConnection *recipient,
1022 - DBusMessage *message,
1023 - DBusError *error);
1024 +BusResult bus_dispatch_matches (BusTransaction *transaction,
1025 + DBusConnection *sender,
1026 + DBusConnection *recipient,
1027 + DBusMessage *message,
1028 + BusDeferredMessage *dispatched_deferred_message,
1029 + DBusError *error);
1031 #endif /* BUS_DISPATCH_H */
1032 diff --git a/bus/driver.c b/bus/driver.c
1033 index 4dbce3d..2fb1385 100644
1036 @@ -130,7 +130,7 @@ bus_driver_send_service_owner_changed (const char *service_name,
1038 _dbus_assert (dbus_message_has_signature (message, "sss"));
1040 - res = bus_dispatch_matches (transaction, NULL, NULL, message, error);
1041 + res = bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error);
1042 if (res == BUS_RESULT_TRUE)
1044 else if (res == BUS_RESULT_FALSE)
1045 diff --git a/bus/policy.c b/bus/policy.c
1046 index ec888df..448147f 100644
1049 @@ -1071,6 +1071,9 @@ bus_client_policy_check_can_send (DBusConnection *sender,
1051 result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
1052 privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
1053 + if (result == BUS_RESULT_LATER && deferred_message != NULL)
1054 + bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
1055 + *toggles, privilege);
1059 @@ -1305,6 +1308,9 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1061 result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
1062 privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
1063 + if (result == BUS_RESULT_LATER && deferred_message != NULL)
1064 + bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
1065 + *toggles, privilege);