1 From fdc3d7086c8f7a623e3da80e559708545b9201fc 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: Handle unavailability of policy results for broadcasts and receive
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
10 When message is sent to the addressed recipient and receive rule
11 result is unavailable we don't want to block the sender
12 as it most likely will be the privileged service, so instead we queue
13 it at the recipient. Any further messages sent to it will be queued to
14 maintain message order. Once the answer from Cynara arrives messages are
15 dispatched from the recipient queue. In such case full dispatch is
16 performed - messages are sent to addressed recipient and other
17 interested connections.
18 Messages sent to non-addressed recipients (eavesdroppers or broadcast
19 message recipients) are handled in a similar way. The difference is
20 that it is not full dispatch meaning message is sent to a single recipient.
22 Cherry picked from 1e231194610892dd4360224998d91336097b05a1 by Jose Bollo
24 Updated for dbus 1.10.20 by Scott Murray and José Bollo
26 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
27 Signed-off-by: Scott Murray <scott.murray@konsulko.com>
29 diff --git a/bus/activation.c b/bus/activation.c
30 index 005047f..ffdc6fc 100644
31 --- a/bus/activation.c
32 +++ b/bus/activation.c
33 @@ -1259,7 +1259,7 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation
34 res = bus_dispatch_matches (transaction,
37 - entry->activation_message, &error);
38 + entry->activation_message, NULL, &error);
39 if (res == BUS_RESULT_FALSE)
41 /* If permission is denied, we just want to return the error
42 @@ -2137,7 +2137,7 @@ bus_activation_activate_service (BusActivation *activation,
43 bus_connection_get_loginfo (connection));
44 /* Wonderful, systemd is connected, let's just send the msg */
45 res = bus_dispatch_matches (activation_transaction, NULL,
46 - systemd, message, error);
47 + systemd, message, NULL, error);
49 if (res == BUS_RESULT_TRUE)
51 diff --git a/bus/bus.c b/bus/bus.c
52 index 237efe3..5bb5637 100644
55 @@ -1800,17 +1800,9 @@ bus_context_check_security_policy (BusContext *context,
58 /* See if limits on size have been exceeded */
59 - if (proposed_recipient &&
60 - ((dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) ||
61 - (dbus_connection_get_outgoing_unix_fds (proposed_recipient) > context->limits.max_outgoing_unix_fds)))
63 - complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
64 - "Rejected: destination has a full message queue",
65 - 0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
67 - _dbus_verbose ("security policy disallowing message due to full message queue\n");
68 + if (!bus_context_check_recipient_message_limits(context, proposed_recipient, sender, message,
69 + requested_reply, error))
70 return BUS_RESULT_FALSE;
73 /* Record that we will allow a reply here in the future (don't
74 * bother if the recipient is the bus or this is an eavesdropping
75 @@ -1869,3 +1861,41 @@ bus_context_check_all_watches (BusContext *context)
76 _dbus_server_toggle_all_watches (server, enabled);
81 +bus_context_complain_about_message (BusContext *context,
82 + const char *error_name,
83 + const char *complaint,
85 + DBusMessage *message,
86 + DBusConnection *sender,
87 + DBusConnection *proposed_recipient,
88 + dbus_bool_t requested_reply,
90 + const char *privilege,
93 + complain_about_message(context, error_name, complaint, matched_rules, message, sender,
94 + proposed_recipient, requested_reply, log, privilege, error);
97 +dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
98 + DBusConnection *recipient,
99 + DBusConnection *sender,
100 + DBusMessage *message,
101 + dbus_bool_t requested_reply,
105 + ((dbus_connection_get_outgoing_size (recipient) > context->limits.max_outgoing_bytes) ||
106 + (dbus_connection_get_outgoing_unix_fds (recipient) > context->limits.max_outgoing_unix_fds)))
108 + complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
109 + "Rejected: destination has a full message queue",
110 + 0, message, sender, recipient, requested_reply, TRUE, NULL,
112 + _dbus_verbose ("security policy disallowing message due to full message queue\n");
117 diff --git a/bus/bus.h b/bus/bus.h
118 index 82c32c8..1b08f7c 100644
121 @@ -164,4 +164,23 @@ BusResult bus_context_check_security_policy (BusContext
122 BusDeferredMessage **deferred_message);
123 void bus_context_check_all_watches (BusContext *context);
125 +dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
126 + DBusConnection *recipient,
127 + DBusConnection *sender,
128 + DBusMessage *message,
129 + dbus_bool_t requested_reply,
131 +void bus_context_complain_about_message (BusContext *context,
132 + const char *error_name,
133 + const char *complaint,
135 + DBusMessage *message,
136 + DBusConnection *sender,
137 + DBusConnection *proposed_recipient,
138 + dbus_bool_t requested_reply,
140 + const char *privilege,
144 #endif /* BUS_BUS_H */
145 diff --git a/bus/check.c b/bus/check.c
146 index 4b8a699..f3d283f 100644
149 @@ -49,6 +49,9 @@ typedef struct BusDeferredMessage
150 DBusConnection *sender;
151 DBusConnection *proposed_recipient;
152 DBusConnection *addressed_recipient;
153 + dbus_bool_t requested_reply;
155 + const char *privilege;
156 dbus_bool_t full_dispatch;
157 BusDeferredMessageStatus status;
159 @@ -135,6 +138,89 @@ bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
160 _dbus_connection_enable_dispatch(deferred_message->sender);
164 +bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
169 + _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
171 + if (!bus_connection_is_active(deferred_message->proposed_recipient))
174 + status = deferred_message->status;
176 + deferred_message->status = 0; /* mark message as not waiting for response */
177 + deferred_message->response = result;
180 + * If send rule allows us to send message we still need to check receive rules.
182 + if ((status & BUS_DEFERRED_MESSAGE_CHECK_SEND) && (result == BUS_RESULT_TRUE))
185 + BusContext *context;
186 + BusRegistry *registry;
187 + BusClientPolicy *recipient_policy;
188 + BusDeferredMessage *deferred_message_receive;
190 + context = bus_connection_get_context(deferred_message->proposed_recipient);
191 + registry = bus_context_get_registry(context);
192 + recipient_policy = bus_connection_get_policy(deferred_message->proposed_recipient);
194 + deferred_message->response = bus_client_policy_check_can_receive(recipient_policy, registry,
195 + deferred_message->requested_reply, deferred_message->sender,
196 + deferred_message->addressed_recipient, deferred_message->proposed_recipient, deferred_message->message,
197 + &toggles, NULL, &deferred_message_receive);
198 + if (deferred_message->response == BUS_RESULT_LATER)
200 + /* replace deferred message associated with send check with the one associated with
202 + if (!bus_deferred_message_replace(deferred_message, deferred_message_receive))
204 + /* failed to replace deferred message (due to oom). Set it to rejected */
205 + deferred_message->response = BUS_RESULT_FALSE;
210 + bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
214 +queue_deferred_message_cancel_transaction_hook (void *data)
216 + BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
217 + bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
222 +bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
223 + BusTransaction *transaction,
224 + dbus_bool_t full_dispatch,
225 + dbus_bool_t prepend)
227 + _dbus_assert(deferred_message != NULL);
228 + _dbus_assert(deferred_message->proposed_recipient != NULL);
230 + if (!bus_connection_queue_deferred_message(deferred_message->proposed_recipient,
231 + deferred_message, prepend))
234 + if (!bus_transaction_add_cancel_hook(transaction, queue_deferred_message_cancel_transaction_hook,
235 + deferred_message, NULL))
237 + bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
240 + deferred_message->response_callback = bus_check_queued_message_reply_callback;
241 + deferred_message->full_dispatch = full_dispatch;
247 deferred_message_free_function(void *data)
249 @@ -159,6 +245,20 @@ bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
250 deferred_message->response_callback = bus_check_enable_dispatch_callback;
254 +bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
255 + dbus_bool_t requested_reply,
257 + const char *privilege)
259 + _dbus_assert(deferred_message != NULL);
261 + deferred_message->requested_reply = requested_reply;
262 + deferred_message->matched_rules = matched_rules;
263 + deferred_message->privilege = privilege;
267 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
268 BusResult (*bus_check_test_override) (DBusConnection *connection,
269 const char *privilege);
270 @@ -259,6 +359,9 @@ BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
271 deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
272 deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
273 deferred_message->message = dbus_message_ref(message);
274 + deferred_message->requested_reply = FALSE;
275 + deferred_message->matched_rules = 0;
276 + deferred_message->privilege = NULL;
277 deferred_message->response = response;
278 deferred_message->status = 0;
279 deferred_message->full_dispatch = FALSE;
280 @@ -295,12 +398,215 @@ bus_deferred_message_unref (BusDeferredMessage *deferred_message)
285 +bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message, DBusError *error)
287 + BusContext *context = bus_connection_get_context(deferred_message->proposed_recipient);
289 + return bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
290 + deferred_message->sender, deferred_message->message, deferred_message->requested_reply,
295 +bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, BusTransaction *transaction, DBusError *error)
297 + int type = dbus_message_get_type(deferred_message->message);
298 + if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
299 + deferred_message->sender &&
300 + deferred_message->addressed_recipient &&
301 + deferred_message->addressed_recipient == deferred_message->proposed_recipient && /* not eavesdropping */
302 + !bus_connections_expect_reply (bus_connection_get_connections (deferred_message->sender),
304 + deferred_message->sender, deferred_message->addressed_recipient,
305 + deferred_message->message, error))
307 + _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
314 +bus_deferred_message_create_error(BusDeferredMessage *deferred_message,
315 + const char *error_message, DBusError *error)
317 + BusContext *context;
318 + _dbus_assert (deferred_message->status == 0 && deferred_message->response == BUS_RESULT_FALSE);
320 + if (deferred_message->sender == NULL)
321 + return; /* error won't be sent to bus driver anyway */
323 + context = bus_connection_get_context(deferred_message->sender);
324 + bus_context_complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected message",
325 + deferred_message->matched_rules, deferred_message->message, deferred_message->sender,
326 + deferred_message->proposed_recipient, deferred_message->requested_reply, FALSE,
327 + deferred_message->privilege, error);
331 +bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
333 + BusContext *context = bus_connection_get_context (deferred_message->proposed_recipient);
334 + BusTransaction *transaction = bus_transaction_new (context);
335 + BusResult result = BUS_RESULT_TRUE;
338 + if (transaction == NULL)
340 + return BUS_RESULT_FALSE;
343 + dbus_error_init(&error);
345 + if (!deferred_message->full_dispatch)
347 + result = deferred_message->response;
348 + if (result == BUS_RESULT_TRUE)
350 + if (!bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
351 + deferred_message->sender, deferred_message->message, deferred_message->requested_reply, &error))
352 + result = BUS_RESULT_FALSE;
354 + else if (result == BUS_RESULT_LATER)
356 + BusDeferredMessage *deferred_message2;
357 + result = bus_context_check_security_policy (context, transaction,
358 + deferred_message->sender,
359 + deferred_message->addressed_recipient,
360 + deferred_message->proposed_recipient,
361 + deferred_message->message, NULL, NULL,
362 + &deferred_message2);
364 + if (result == BUS_RESULT_LATER)
366 + /* prepend at recipient */
367 + if (!bus_deferred_message_queue_at_recipient(deferred_message2, transaction,
369 + result = BUS_RESULT_FALSE;
373 + /* silently drop messages on access denial */
374 + if (result == BUS_RESULT_TRUE)
376 + if (!bus_transaction_send (transaction, deferred_message->proposed_recipient, deferred_message->message, TRUE))
377 + result = BUS_RESULT_FALSE;
380 + bus_transaction_execute_and_free(transaction);
385 + /* do not attempt to send message if sender has disconnected */
386 + if (deferred_message->sender != NULL && !bus_connection_is_active(deferred_message->sender))
388 + bus_transaction_cancel_and_free(transaction);
389 + result = BUS_RESULT_FALSE;
393 + result = bus_dispatch_matches(transaction, deferred_message->sender,
394 + deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
396 + if (result == BUS_RESULT_LATER)
398 + /* Message deferring was already done in bus_dispatch_matches */
399 + bus_transaction_cancel_and_free(transaction);
403 + /* this part is a copy & paste from bus_dispatch function. Probably can be moved to a function */
404 + if (dbus_error_is_set (&error))
406 + if (!dbus_connection_get_is_connected (deferred_message->sender))
408 + /* If we disconnected it, we won't bother to send it any error
411 + _dbus_verbose ("Not sending error to connection we disconnected\n");
413 + else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
415 + bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
417 + /* cancel transaction due to OOM */
418 + if (transaction != NULL)
420 + bus_transaction_cancel_and_free (transaction);
421 + transaction = NULL;
426 + /* Try to send the real error, if no mem to do that, send
429 + _dbus_assert (transaction != NULL);
430 + if (!bus_transaction_send_error_reply (transaction, deferred_message->sender,
431 + &error, deferred_message->message))
433 + bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
435 + /* cancel transaction due to OOM */
436 + if (transaction != NULL)
438 + bus_transaction_cancel_and_free (transaction);
439 + transaction = NULL;
445 + if (transaction != NULL)
447 + bus_transaction_execute_and_free (transaction);
451 + dbus_error_free(&error);
457 +bus_deferred_message_replace (BusDeferredMessage *old_message, BusDeferredMessage *new_message)
459 + if (bus_connection_replace_deferred_message(old_message->proposed_recipient,
460 + old_message, new_message))
462 + new_message->response_callback = old_message->response_callback;
463 + new_message->full_dispatch = old_message->full_dispatch;
470 +bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
472 + return deferred_message->status != 0;
476 +bus_deferred_message_get_recipient(BusDeferredMessage *deferred_message)
478 + return deferred_message->proposed_recipient;
481 BusDeferredMessageStatus
482 bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
484 return deferred_message->status;
488 +bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
490 + return deferred_message->response;
494 bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
496 @@ -310,3 +616,4 @@ bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
497 deferred_message->response_callback(deferred_message, result);
501 diff --git a/bus/check.h b/bus/check.h
502 index d177549..9c13c18 100644
505 @@ -64,12 +64,37 @@ BusDeferredMessage *bus_deferred_message_new (DBusMessage *messag
507 BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message);
508 void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
509 +BusResult bus_deferred_message_dispatch (BusDeferredMessage *deferred_message);
510 +dbus_bool_t bus_deferred_message_waits_for_check (BusDeferredMessage *deferred_message);
511 +DBusConnection *bus_deferred_message_get_recipient (BusDeferredMessage *deferred_message);
512 void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
514 +dbus_bool_t bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
515 + BusTransaction *transaction,
516 + dbus_bool_t full_dispatch,
517 + dbus_bool_t prepend);
518 +dbus_bool_t bus_deferred_message_replace (BusDeferredMessage *old_message,
519 + BusDeferredMessage *new_message);
520 void bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message);
521 +BusResult bus_deferred_message_get_response (BusDeferredMessage *deferred_message);
523 BusDeferredMessageStatus bus_deferred_message_get_status (BusDeferredMessage *deferred_message);
526 +dbus_bool_t bus_deferred_message_expect_method_reply (BusDeferredMessage *deferred_message,
527 + BusTransaction *transaction,
529 +void bus_deferred_message_create_error (BusDeferredMessage *deferred_message,
530 + const char *error_message,
532 +void bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
533 + dbus_bool_t requested_reply,
535 + const char *privilege);
536 +dbus_bool_t bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message,
540 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
541 extern BusResult (*bus_check_test_override) (DBusConnection *connection,
542 const char *privilege);
543 diff --git a/bus/connection.c b/bus/connection.c
544 index b348d42..ee93384 100644
545 --- a/bus/connection.c
546 +++ b/bus/connection.c
548 #include "expirelist.h"
550 #include "apparmor.h"
552 #include <dbus/dbus-list.h>
553 #include <dbus/dbus-hash.h>
554 #include <dbus/dbus-timeout.h>
555 #include <dbus/dbus-connection-internal.h>
556 #include <dbus/dbus-internals.h>
557 +#include <dbus/dbus-message-internal.h>
558 #ifdef DBUS_ENABLE_CYNARA
560 #include <cynara-session.h>
561 @@ -102,6 +104,7 @@ typedef struct
562 DBusMessage *oom_message;
563 DBusPreallocatedSend *oom_preallocated;
564 BusClientPolicy *policy;
565 + DBusList *deferred_messages; /**< Queue of messages deferred due to pending policy check */
567 char *cached_loginfo_string;
568 BusSELinuxID *selinux_id;
569 @@ -268,6 +271,8 @@ bus_connection_disconnected (DBusConnection *connection)
570 bus_transaction_execute_and_free (transaction);
573 + bus_connection_clear_deferred_messages(connection);
575 bus_dispatch_remove_connection (connection);
577 /* no more watching */
578 @@ -2307,7 +2312,7 @@ bus_transaction_capture (BusTransaction *transaction,
580 DBusConnection *recipient = link->data;
582 - if (!bus_transaction_send (transaction, recipient, message))
583 + if (!bus_transaction_send (transaction, recipient, message, FALSE))
587 @@ -2361,6 +2366,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
589 DBusError error = DBUS_ERROR_INIT;
591 + BusDeferredMessage *deferred_message;
593 /* We have to set the sender to the driver, and have
594 * to check security policy since it was not done in
595 @@ -2401,7 +2407,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
596 res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
598 NULL, connection, connection, message, NULL,
600 + &error, &deferred_message);
601 if (res == BUS_RESULT_FALSE)
603 if (!bus_transaction_capture_error_reply (transaction, connection,
604 @@ -2419,18 +2425,20 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
606 else if (res == BUS_RESULT_LATER)
608 - _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
609 dbus_error_free (&error);
611 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
613 + return TRUE; /* pretend to have sent it */
616 - return bus_transaction_send (transaction, connection, message);
617 + return bus_transaction_send (transaction, connection, message, FALSE);
621 bus_transaction_send (BusTransaction *transaction,
622 DBusConnection *connection,
623 - DBusMessage *message)
624 + DBusMessage *message,
625 + dbus_bool_t deferred_dispatch)
627 MessageToSend *to_send;
628 BusConnectionData *d;
629 @@ -2456,7 +2464,28 @@ bus_transaction_send (BusTransaction *transaction,
631 d = BUS_CONNECTION_DATA (connection);
632 _dbus_assert (d != NULL);
635 + if (!deferred_dispatch && d->deferred_messages != NULL)
637 + BusDeferredMessage *deferred_message;
638 + dbus_bool_t success;
639 + /* sender and addressed recipient are not required at this point as we only need to send message
640 + * to a single recipient without performing policy check. */
641 + deferred_message = bus_deferred_message_new (message,
646 + if (deferred_message == NULL)
649 + success = bus_deferred_message_queue_at_recipient(deferred_message, transaction,
651 + bus_deferred_message_unref(deferred_message);
656 to_send = dbus_new (MessageToSend, 1);
659 @@ -2708,6 +2737,131 @@ bus_transaction_add_cancel_hook (BusTransaction *transaction,
664 +bus_connection_dispatch_deferred (DBusConnection *connection)
666 + BusDeferredMessage *message;
668 + _dbus_return_if_fail (connection != NULL);
670 + while ((message = bus_connection_pop_deferred_message(connection)) != NULL)
672 + bus_deferred_message_dispatch(message);
673 + bus_deferred_message_unref(message);
678 +bus_connection_has_deferred_messages (DBusConnection *connection)
680 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
681 + return d->deferred_messages != NULL ? TRUE : FALSE;
685 +bus_connection_queue_deferred_message (DBusConnection *connection,
686 + BusDeferredMessage *message,
687 + dbus_bool_t prepend)
689 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
690 + dbus_bool_t success;
692 + success = _dbus_list_prepend(&d->deferred_messages, message);
694 + success = _dbus_list_append(&d->deferred_messages, message);
698 + bus_deferred_message_ref(message);
706 +bus_connection_replace_deferred_message (DBusConnection *connection,
707 + BusDeferredMessage *oldMessage,
708 + BusDeferredMessage *newMessage)
711 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
713 + link = _dbus_list_find_first(&d->deferred_messages, oldMessage);
717 + if (!_dbus_list_insert_after(&d->deferred_messages, link, newMessage))
720 + bus_deferred_message_ref(newMessage);
721 + _dbus_list_remove_link(&d->deferred_messages, link);
722 + bus_deferred_message_unref(oldMessage);
726 +BusDeferredMessage *
727 +bus_connection_pop_deferred_message (DBusConnection *connection)
730 + BusDeferredMessage *message;
731 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
733 + link =_dbus_list_get_first_link(&d->deferred_messages);
736 + message = link->data;
737 + if (!bus_deferred_message_waits_for_check(message))
739 + _dbus_list_remove_link(&d->deferred_messages, link);
748 +bus_connection_putback_deferred_message (DBusConnection *connection, BusDeferredMessage *message)
750 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
751 + if (_dbus_list_prepend(&d->deferred_messages, message))
759 +bus_connection_clear_deferred_messages (DBusConnection *connection)
761 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
764 + BusDeferredMessage *message;
766 + link =_dbus_list_get_first_link(&d->deferred_messages);
767 + while (link != NULL)
769 + next = _dbus_list_get_next_link (&d->deferred_messages, link);
770 + message = link->data;
772 + bus_deferred_message_unref(message);
773 + _dbus_list_remove_link(&d->deferred_messages, link);
780 +bus_connection_remove_deferred_message (DBusConnection *connection,
781 + BusDeferredMessage *message)
783 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
784 + if (_dbus_list_remove(&d->deferred_messages, message))
785 + bus_deferred_message_unref(message);
789 bus_connections_get_n_active (BusConnections *connections)
791 diff --git a/bus/connection.h b/bus/connection.h
792 index 71078ea..97dae96 100644
793 --- a/bus/connection.h
794 +++ b/bus/connection.h
795 @@ -85,6 +85,22 @@ dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection);
796 void bus_connection_send_oom_error (DBusConnection *connection,
797 DBusMessage *in_reply_to);
799 +dbus_bool_t bus_connection_has_deferred_messages (DBusConnection *connection);
800 +dbus_bool_t bus_connection_queue_deferred_message (DBusConnection *connection,
801 + BusDeferredMessage *message,
802 + dbus_bool_t prepend);
803 +BusDeferredMessage *bus_connection_pop_deferred_message (DBusConnection *connection);
804 +dbus_bool_t bus_connection_putback_deferred_message (DBusConnection *connection,
805 + BusDeferredMessage *message);
806 +void bus_connection_remove_deferred_message (DBusConnection *connection,
807 + BusDeferredMessage *message);
808 +dbus_bool_t bus_connection_replace_deferred_message (DBusConnection *connection,
809 + BusDeferredMessage *oldMessage,
810 + BusDeferredMessage *newMessage);
811 +void bus_connection_dispatch_deferred (DBusConnection *connection);
812 +void bus_connection_clear_deferred_messages (DBusConnection *connection);
815 /* called by signals.c */
816 dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection,
818 @@ -137,7 +153,8 @@ BusTransaction* bus_transaction_new (BusContext *
819 BusContext* bus_transaction_get_context (BusTransaction *transaction);
820 dbus_bool_t bus_transaction_send (BusTransaction *transaction,
821 DBusConnection *connection,
822 - DBusMessage *message);
823 + DBusMessage *message,
824 + dbus_bool_t deferred_dispatch);
825 dbus_bool_t bus_transaction_capture (BusTransaction *transaction,
826 DBusConnection *connection,
827 DBusConnection *addressed_recipient,
828 diff --git a/bus/dispatch.c b/bus/dispatch.c
829 index 50a22a3..7d30ce4 100644
836 +#include "dispatch.h"
838 #include <dbus/dbus-internals.h>
839 #include <dbus/dbus-connection-internal.h>
840 @@ -77,7 +78,7 @@ send_one_message (DBusConnection *connection,
844 - if (result != BUS_RESULT_TRUE)
845 + if (result == BUS_RESULT_FALSE)
847 if (!bus_transaction_capture_error_reply (transaction, sender,
848 &stack_error, message))
849 @@ -112,9 +113,19 @@ send_one_message (DBusConnection *connection,
850 return TRUE; /* don't send it but don't return an error either */
853 + if (result == BUS_RESULT_LATER)
855 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
857 + BUS_SET_OOM (error);
860 + return TRUE; /* pretend to have sent it */
863 if (!bus_transaction_send (transaction,
870 @@ -124,11 +135,12 @@ send_one_message (DBusConnection *connection,
874 -bus_dispatch_matches (BusTransaction *transaction,
875 - DBusConnection *sender,
876 - DBusConnection *addressed_recipient,
877 - DBusMessage *message,
879 +bus_dispatch_matches (BusTransaction *transaction,
880 + DBusConnection *sender,
881 + DBusConnection *addressed_recipient,
882 + DBusMessage *message,
883 + BusDeferredMessage *dispatched_deferred_message,
887 BusConnections *connections;
888 @@ -137,7 +149,6 @@ bus_dispatch_matches (BusTransaction *transaction,
891 BusDeferredMessage *deferred_message;
894 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
896 @@ -153,16 +164,80 @@ bus_dispatch_matches (BusTransaction *transaction,
897 /* First, send the message to the addressed_recipient, if there is one. */
898 if (addressed_recipient != NULL)
900 - res = bus_context_check_security_policy (context, transaction,
902 + /* To maintain message order message needs to be appended at the recipient if there are already
903 + * deferred messages and we are not doing deferred dispatch
905 + if (dispatched_deferred_message == NULL && bus_connection_has_deferred_messages(addressed_recipient))
907 + deferred_message = bus_deferred_message_new(message, sender,
908 + addressed_recipient, addressed_recipient, BUS_RESULT_LATER);
910 + if (deferred_message == NULL)
912 + BUS_SET_OOM(error);
913 + return BUS_RESULT_FALSE;
916 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
918 + bus_deferred_message_unref(deferred_message);
919 + BUS_SET_OOM(error);
920 + return BUS_RESULT_FALSE;
923 + bus_deferred_message_unref(deferred_message);
924 + return BUS_RESULT_TRUE; /* pretend to have sent it */
927 + if (dispatched_deferred_message != NULL)
929 + result = bus_deferred_message_get_response(dispatched_deferred_message);
930 + if (result == BUS_RESULT_TRUE)
932 + /* if we know the result of policy check we still need to check if message limits
933 + * are not exceeded. It is also required to add entry in expected replies list if
934 + * this is a method call
936 + if (!bus_deferred_message_check_message_limits(dispatched_deferred_message, error))
937 + return BUS_RESULT_FALSE;
939 + if (!bus_deferred_message_expect_method_reply(dispatched_deferred_message, transaction, error))
940 + return BUS_RESULT_FALSE;
942 + else if (result == BUS_RESULT_FALSE)
944 + bus_deferred_message_create_error(dispatched_deferred_message, "Rejected message", error);
945 + return BUS_RESULT_FALSE;
949 + result = BUS_RESULT_LATER;
951 + if (result == BUS_RESULT_LATER)
952 + result = bus_context_check_security_policy (context, transaction,
953 sender, addressed_recipient,
955 message, NULL, error,
957 - if (res == BUS_RESULT_FALSE)
959 + if (result == BUS_RESULT_FALSE)
960 return BUS_RESULT_FALSE;
961 - else if (res == BUS_RESULT_LATER)
962 + else if (result == BUS_RESULT_LATER)
964 BusDeferredMessageStatus status;
966 + if (dispatched_deferred_message != NULL)
968 + /* for deferred dispatch prepend message at the recipient */
969 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, TRUE))
971 + BUS_SET_OOM(error);
972 + return BUS_RESULT_FALSE;
974 + return BUS_RESULT_TRUE; /* pretend to have sent it */
977 status = bus_deferred_message_get_status(deferred_message);
979 if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
980 @@ -173,13 +248,18 @@ bus_dispatch_matches (BusTransaction *transaction,
982 else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
984 - dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
985 - "Rejecting message because time is needed to check security policy");
986 - return BUS_RESULT_FALSE;
987 + /* receive rule result not available - queue message at the recipient */
988 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
990 + BUS_SET_OOM(error);
991 + return BUS_RESULT_FALSE;
994 + return BUS_RESULT_TRUE; /* pretend to have sent it */
998 - _dbus_verbose("deferred message has no status field set to send or receive unexpectedly\n");
999 + _dbus_verbose("deferred message has no status field set unexpectedly\n");
1000 return BUS_RESULT_FALSE;
1003 @@ -196,7 +276,8 @@ bus_dispatch_matches (BusTransaction *transaction,
1006 /* Dispatch the message */
1007 - if (!bus_transaction_send (transaction, addressed_recipient, message))
1008 + if (!bus_transaction_send(transaction, addressed_recipient, message,
1009 + dispatched_deferred_message != NULL ? TRUE : FALSE))
1011 BUS_SET_OOM (error);
1012 return BUS_RESULT_FALSE;
1013 @@ -534,7 +615,7 @@ bus_dispatch (DBusConnection *connection,
1016 if (BUS_RESULT_LATER == bus_dispatch_matches (transaction, connection, addressed_recipient,
1018 + message, NULL, &error))
1020 /* Roll back and dispatch the message once the policy result is available */
1021 bus_transaction_cancel_and_free (transaction);
1022 diff --git a/bus/dispatch.h b/bus/dispatch.h
1023 index afba6a2..f6102e8 100644
1024 --- a/bus/dispatch.h
1025 +++ b/bus/dispatch.h
1028 dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection);
1029 void bus_dispatch_remove_connection (DBusConnection *connection);
1030 -BusResult bus_dispatch_matches (BusTransaction *transaction,
1031 - DBusConnection *sender,
1032 - DBusConnection *recipient,
1033 - DBusMessage *message,
1034 - DBusError *error);
1035 +BusResult bus_dispatch_matches (BusTransaction *transaction,
1036 + DBusConnection *sender,
1037 + DBusConnection *recipient,
1038 + DBusMessage *message,
1039 + BusDeferredMessage *dispatched_deferred_message,
1040 + DBusError *error);
1042 #endif /* BUS_DISPATCH_H */
1043 diff --git a/bus/driver.c b/bus/driver.c
1044 index f414f64..d89a658 100644
1047 @@ -254,7 +254,7 @@ bus_driver_send_service_owner_changed (const char *service_name,
1048 if (!bus_transaction_capture (transaction, NULL, NULL, message))
1051 - res = bus_dispatch_matches (transaction, NULL, NULL, message, error);
1052 + res = bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error);
1053 if (res == BUS_RESULT_TRUE)
1056 diff --git a/bus/policy.c b/bus/policy.c
1057 index 7ee1ce5..b1fab0d 100644
1060 @@ -1121,6 +1121,9 @@ bus_client_policy_check_can_send (DBusConnection *sender,
1062 result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
1063 privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
1064 + if (result == BUS_RESULT_LATER && deferred_message != NULL)
1065 + bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
1066 + *toggles, privilege);
1070 @@ -1370,6 +1373,9 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1072 result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
1073 privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
1074 + if (result == BUS_RESULT_LATER && deferred_message != NULL)
1075 + bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
1076 + *toggles, privilege);