1 From 8c5fd05f7b2f14ac0f4423cae300f60c6bb51c74 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 3/5] Handle unavailability of policy results for broadcasts
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 Change-Id: Iecd5395f75a4c7811fa97247a37d8fc4d42e8814
24 Cherry picked from 1e231194610892dd4360224998d91336097b05a1 by Jose Bollo
26 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
28 bus/activation.c | 4 +-
29 bus/bus.c | 50 +++++++--
31 bus/check.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
32 bus/check.h | 25 +++++
33 bus/connection.c | 169 ++++++++++++++++++++++++++++--
34 bus/connection.h | 19 +++-
35 bus/dispatch.c | 121 ++++++++++++++++++----
36 bus/dispatch.h | 11 +-
39 11 files changed, 686 insertions(+), 47 deletions(-)
41 diff --git a/bus/activation.c b/bus/activation.c
42 index 343d3f22..11bd8386 100644
43 --- a/bus/activation.c
44 +++ b/bus/activation.c
45 @@ -1198,7 +1198,7 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation
46 res = bus_dispatch_matches (transaction,
49 - entry->activation_message, &error);
50 + entry->activation_message, NULL, &error);
51 if (res == BUS_RESULT_FALSE)
53 /* If permission is denied, we just want to return the error
54 @@ -2085,7 +2085,7 @@ bus_activation_activate_service (BusActivation *activation,
55 entry->systemd_service);
56 /* Wonderful, systemd is connected, let's just send the msg */
57 res = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service),
59 + message, NULL, error);
61 if (res == BUS_RESULT_TRUE)
63 diff --git a/bus/bus.c b/bus/bus.c
64 index c4008505..911e2340 100644
67 @@ -1796,17 +1796,9 @@ bus_context_check_security_policy (BusContext *context,
70 /* See if limits on size have been exceeded */
71 - if (proposed_recipient &&
72 - ((dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) ||
73 - (dbus_connection_get_outgoing_unix_fds (proposed_recipient) > context->limits.max_outgoing_unix_fds)))
75 - complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
76 - "Rejected: destination has a full message queue",
77 - 0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
79 - _dbus_verbose ("security policy disallowing message due to full message queue\n");
80 + if (!bus_context_check_recipient_message_limits(context, proposed_recipient, sender, message,
81 + requested_reply, error))
82 return BUS_RESULT_FALSE;
85 /* Record that we will allow a reply here in the future (don't
86 * bother if the recipient is the bus or this is an eavesdropping
87 @@ -1861,3 +1853,41 @@ bus_context_check_all_watches (BusContext *context)
88 _dbus_server_toggle_all_watches (server, enabled);
93 +bus_context_complain_about_message (BusContext *context,
94 + const char *error_name,
95 + const char *complaint,
97 + DBusMessage *message,
98 + DBusConnection *sender,
99 + DBusConnection *proposed_recipient,
100 + dbus_bool_t requested_reply,
102 + const char *privilege,
105 + complain_about_message(context, error_name, complaint, matched_rules, message, sender,
106 + proposed_recipient, requested_reply, log, privilege, error);
109 +dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
110 + DBusConnection *recipient,
111 + DBusConnection *sender,
112 + DBusMessage *message,
113 + dbus_bool_t requested_reply,
117 + ((dbus_connection_get_outgoing_size (recipient) > context->limits.max_outgoing_bytes) ||
118 + (dbus_connection_get_outgoing_unix_fds (recipient) > context->limits.max_outgoing_unix_fds)))
120 + complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
121 + "Rejected: destination has a full message queue",
122 + 0, message, sender, recipient, requested_reply, TRUE, NULL,
124 + _dbus_verbose ("security policy disallowing message due to full message queue\n");
129 diff --git a/bus/bus.h b/bus/bus.h
130 index dab7791f..445165c9 100644
133 @@ -158,4 +158,23 @@ BusResult bus_context_check_security_policy (BusContext
134 BusDeferredMessage **deferred_message);
135 void bus_context_check_all_watches (BusContext *context);
137 +dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
138 + DBusConnection *recipient,
139 + DBusConnection *sender,
140 + DBusMessage *message,
141 + dbus_bool_t requested_reply,
143 +void bus_context_complain_about_message (BusContext *context,
144 + const char *error_name,
145 + const char *complaint,
147 + DBusMessage *message,
148 + DBusConnection *sender,
149 + DBusConnection *proposed_recipient,
150 + dbus_bool_t requested_reply,
152 + const char *privilege,
156 #endif /* BUS_BUS_H */
157 diff --git a/bus/check.c b/bus/check.c
158 index 4b8a6994..b8833349 100644
161 @@ -49,6 +49,9 @@ typedef struct BusDeferredMessage
162 DBusConnection *sender;
163 DBusConnection *proposed_recipient;
164 DBusConnection *addressed_recipient;
165 + dbus_bool_t requested_reply;
167 + const char *privilege;
168 dbus_bool_t full_dispatch;
169 BusDeferredMessageStatus status;
171 @@ -135,6 +138,89 @@ bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
172 _dbus_connection_enable_dispatch(deferred_message->sender);
176 +bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
181 + _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
183 + if (!bus_connection_is_active(deferred_message->proposed_recipient))
186 + status = deferred_message->status;
188 + deferred_message->status = 0; /* mark message as not waiting for response */
189 + deferred_message->response = result;
192 + * If send rule allows us to send message we still need to check receive rules.
194 + if ((status & BUS_DEFERRED_MESSAGE_CHECK_SEND) && (result == BUS_RESULT_TRUE))
197 + BusContext *context;
198 + BusRegistry *registry;
199 + BusClientPolicy *recipient_policy;
200 + BusDeferredMessage *deferred_message_receive;
202 + context = bus_connection_get_context(deferred_message->proposed_recipient);
203 + registry = bus_context_get_registry(context);
204 + recipient_policy = bus_connection_get_policy(deferred_message->proposed_recipient);
206 + deferred_message->response = bus_client_policy_check_can_receive(recipient_policy, registry,
207 + deferred_message->requested_reply, deferred_message->sender,
208 + deferred_message->addressed_recipient, deferred_message->proposed_recipient, deferred_message->message,
209 + &toggles, NULL, &deferred_message_receive);
210 + if (deferred_message->response == BUS_RESULT_LATER)
212 + /* replace deferred message associated with send check with the one associated with
214 + if (!bus_deferred_message_replace(deferred_message, deferred_message_receive))
216 + /* failed to replace deferred message (due to oom). Set it to rejected */
217 + deferred_message->response = BUS_RESULT_FALSE;
222 + bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
226 +queue_deferred_message_cancel_transaction_hook (void *data)
228 + BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
229 + bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
234 +bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
235 + BusTransaction *transaction,
236 + dbus_bool_t full_dispatch,
237 + dbus_bool_t prepend)
239 + _dbus_assert(deferred_message != NULL);
240 + _dbus_assert(deferred_message->proposed_recipient != NULL);
242 + if (!bus_connection_queue_deferred_message(deferred_message->proposed_recipient,
243 + deferred_message, prepend))
246 + if (!bus_transaction_add_cancel_hook(transaction, queue_deferred_message_cancel_transaction_hook,
247 + deferred_message, NULL))
249 + bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
252 + deferred_message->response_callback = bus_check_queued_message_reply_callback;
253 + deferred_message->full_dispatch = full_dispatch;
259 deferred_message_free_function(void *data)
261 @@ -159,6 +245,20 @@ bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
262 deferred_message->response_callback = bus_check_enable_dispatch_callback;
266 +bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
267 + dbus_bool_t requested_reply,
269 + const char *privilege)
271 + _dbus_assert(deferred_message != NULL);
273 + deferred_message->requested_reply = requested_reply;
274 + deferred_message->matched_rules = matched_rules;
275 + deferred_message->privilege = privilege;
279 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
280 BusResult (*bus_check_test_override) (DBusConnection *connection,
281 const char *privilege);
282 @@ -259,6 +359,9 @@ BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
283 deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
284 deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
285 deferred_message->message = dbus_message_ref(message);
286 + deferred_message->requested_reply = FALSE;
287 + deferred_message->matched_rules = 0;
288 + deferred_message->privilege = NULL;
289 deferred_message->response = response;
290 deferred_message->status = 0;
291 deferred_message->full_dispatch = FALSE;
292 @@ -295,12 +398,215 @@ bus_deferred_message_unref (BusDeferredMessage *deferred_message)
297 +bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message, DBusError *error)
299 + BusContext *context = bus_connection_get_context(deferred_message->proposed_recipient);
301 + return bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
302 + deferred_message->sender, deferred_message->message, deferred_message->requested_reply,
307 +bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, BusTransaction *transaction, DBusError *error)
309 + int type = dbus_message_get_type(deferred_message->message);
310 + if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
311 + deferred_message->sender &&
312 + deferred_message->addressed_recipient &&
313 + deferred_message->addressed_recipient == deferred_message->proposed_recipient && /* not eavesdropping */
314 + !bus_connections_expect_reply (bus_connection_get_connections (deferred_message->sender),
316 + deferred_message->sender, deferred_message->addressed_recipient,
317 + deferred_message->message, error))
319 + _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
326 +bus_deferred_message_create_error(BusDeferredMessage *deferred_message,
327 + const char *error_message, DBusError *error)
329 + BusContext *context;
330 + _dbus_assert (deferred_message->status == 0 && deferred_message->response == BUS_RESULT_FALSE);
332 + if (deferred_message->sender == NULL)
333 + return; /* error won't be sent to bus driver anyway */
335 + context = bus_connection_get_context(deferred_message->sender);
336 + bus_context_complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected message",
337 + deferred_message->matched_rules, deferred_message->message, deferred_message->sender,
338 + deferred_message->proposed_recipient, deferred_message->requested_reply, FALSE,
339 + deferred_message->privilege, error);
343 +bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
345 + BusContext *context = bus_connection_get_context (deferred_message->proposed_recipient);
346 + BusTransaction *transaction = bus_transaction_new (context);
347 + BusResult result = BUS_RESULT_TRUE;
350 + if (transaction == NULL)
352 + return BUS_RESULT_FALSE;
355 + dbus_error_init(&error);
357 + if (!deferred_message->full_dispatch)
359 + result = deferred_message->response;
360 + if (result == BUS_RESULT_TRUE)
362 + if (!bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
363 + deferred_message->sender, deferred_message->message, deferred_message->requested_reply, &error))
364 + result = BUS_RESULT_FALSE;
366 + else if (result == BUS_RESULT_LATER)
368 + BusDeferredMessage *deferred_message2;
369 + result = bus_context_check_security_policy (context, transaction,
370 + deferred_message->sender,
371 + deferred_message->addressed_recipient,
372 + deferred_message->proposed_recipient,
373 + deferred_message->message, NULL,
374 + &deferred_message2);
376 + if (result == BUS_RESULT_LATER)
378 + /* prepend at recipient */
379 + if (!bus_deferred_message_queue_at_recipient(deferred_message2, transaction,
381 + result = BUS_RESULT_FALSE;
385 + /* silently drop messages on access denial */
386 + if (result == BUS_RESULT_TRUE)
388 + if (!bus_transaction_send (transaction, deferred_message->proposed_recipient, deferred_message->message, TRUE))
389 + result = BUS_RESULT_FALSE;
392 + bus_transaction_execute_and_free(transaction);
397 + /* do not attempt to send message if sender has disconnected */
398 + if (deferred_message->sender != NULL && !bus_connection_is_active(deferred_message->sender))
400 + bus_transaction_cancel_and_free(transaction);
401 + result = BUS_RESULT_FALSE;
405 + result = bus_dispatch_matches(transaction, deferred_message->sender,
406 + deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
408 + if (result == BUS_RESULT_LATER)
410 + /* Message deferring was already done in bus_dispatch_matches */
411 + bus_transaction_cancel_and_free(transaction);
415 + /* this part is a copy & paste from bus_dispatch function. Probably can be moved to a function */
416 + if (dbus_error_is_set (&error))
418 + if (!dbus_connection_get_is_connected (deferred_message->sender))
420 + /* If we disconnected it, we won't bother to send it any error
423 + _dbus_verbose ("Not sending error to connection we disconnected\n");
425 + else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
427 + bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
429 + /* cancel transaction due to OOM */
430 + if (transaction != NULL)
432 + bus_transaction_cancel_and_free (transaction);
433 + transaction = NULL;
438 + /* Try to send the real error, if no mem to do that, send
441 + _dbus_assert (transaction != NULL);
442 + if (!bus_transaction_send_error_reply (transaction, deferred_message->sender,
443 + &error, deferred_message->message))
445 + bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
447 + /* cancel transaction due to OOM */
448 + if (transaction != NULL)
450 + bus_transaction_cancel_and_free (transaction);
451 + transaction = NULL;
457 + if (transaction != NULL)
459 + bus_transaction_execute_and_free (transaction);
463 + dbus_error_free(&error);
469 +bus_deferred_message_replace (BusDeferredMessage *old_message, BusDeferredMessage *new_message)
471 + if (bus_connection_replace_deferred_message(old_message->proposed_recipient,
472 + old_message, new_message))
474 + new_message->response_callback = old_message->response_callback;
475 + new_message->full_dispatch = old_message->full_dispatch;
482 +bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
484 + return deferred_message->status != 0;
488 +bus_deferred_message_get_recipient(BusDeferredMessage *deferred_message)
490 + return deferred_message->proposed_recipient;
493 BusDeferredMessageStatus
494 bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
496 return deferred_message->status;
500 +bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
502 + return deferred_message->response;
506 bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
508 @@ -310,3 +616,4 @@ bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
509 deferred_message->response_callback(deferred_message, result);
513 diff --git a/bus/check.h b/bus/check.h
514 index d1775497..9c13c184 100644
517 @@ -64,12 +64,37 @@ BusDeferredMessage *bus_deferred_message_new (DBusMessage *messag
519 BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message);
520 void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
521 +BusResult bus_deferred_message_dispatch (BusDeferredMessage *deferred_message);
522 +dbus_bool_t bus_deferred_message_waits_for_check (BusDeferredMessage *deferred_message);
523 +DBusConnection *bus_deferred_message_get_recipient (BusDeferredMessage *deferred_message);
524 void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
526 +dbus_bool_t bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
527 + BusTransaction *transaction,
528 + dbus_bool_t full_dispatch,
529 + dbus_bool_t prepend);
530 +dbus_bool_t bus_deferred_message_replace (BusDeferredMessage *old_message,
531 + BusDeferredMessage *new_message);
532 void bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message);
533 +BusResult bus_deferred_message_get_response (BusDeferredMessage *deferred_message);
535 BusDeferredMessageStatus bus_deferred_message_get_status (BusDeferredMessage *deferred_message);
538 +dbus_bool_t bus_deferred_message_expect_method_reply (BusDeferredMessage *deferred_message,
539 + BusTransaction *transaction,
541 +void bus_deferred_message_create_error (BusDeferredMessage *deferred_message,
542 + const char *error_message,
544 +void bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
545 + dbus_bool_t requested_reply,
547 + const char *privilege);
548 +dbus_bool_t bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message,
552 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
553 extern BusResult (*bus_check_test_override) (DBusConnection *connection,
554 const char *privilege);
555 diff --git a/bus/connection.c b/bus/connection.c
556 index eea50ecd..1c0bdffb 100644
557 --- a/bus/connection.c
558 +++ b/bus/connection.c
560 #include "expirelist.h"
562 #include "apparmor.h"
564 #include <dbus/dbus-list.h>
565 #include <dbus/dbus-hash.h>
566 #include <dbus/dbus-timeout.h>
567 #include <dbus/dbus-connection-internal.h>
568 #include <dbus/dbus-internals.h>
569 +#include <dbus/dbus-message-internal.h>
570 #ifdef DBUS_ENABLE_CYNARA
572 #include <cynara-session.h>
573 @@ -102,6 +104,7 @@ typedef struct
574 DBusMessage *oom_message;
575 DBusPreallocatedSend *oom_preallocated;
576 BusClientPolicy *policy;
577 + DBusList *deferred_messages; /**< Queue of messages deferred due to pending policy check */
579 char *cached_loginfo_string;
580 BusSELinuxID *selinux_id;
581 @@ -268,6 +271,8 @@ bus_connection_disconnected (DBusConnection *connection)
582 bus_transaction_execute_and_free (transaction);
585 + bus_connection_clear_deferred_messages(connection);
587 bus_dispatch_remove_connection (connection);
589 /* no more watching */
590 @@ -2264,7 +2269,7 @@ bus_transaction_capture (BusTransaction *transaction,
592 DBusConnection *recipient = link->data;
594 - if (!bus_transaction_send (transaction, recipient, message))
595 + if (!bus_transaction_send (transaction, recipient, message, FALSE))
599 @@ -2317,6 +2322,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
601 DBusError error = DBUS_ERROR_INIT;
603 + BusDeferredMessage *deferred_message;
605 /* We have to set the sender to the driver, and have
606 * to check security policy since it was not done in
607 @@ -2357,7 +2363,8 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
608 res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
610 NULL, connection, connection, message, &error,
612 + &deferred_message);
614 if (res == BUS_RESULT_FALSE)
616 if (!bus_transaction_capture_error_reply (transaction, &error, message))
617 @@ -2374,18 +2381,20 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
619 else if (res == BUS_RESULT_LATER)
621 - _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
622 dbus_error_free (&error);
624 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
626 + return TRUE; /* pretend to have sent it */
629 - return bus_transaction_send (transaction, connection, message);
630 + return bus_transaction_send (transaction, connection, message, FALSE);
634 bus_transaction_send (BusTransaction *transaction,
635 DBusConnection *connection,
636 - DBusMessage *message)
637 + DBusMessage *message,
638 + dbus_bool_t deferred_dispatch)
640 MessageToSend *to_send;
641 BusConnectionData *d;
642 @@ -2411,7 +2420,28 @@ bus_transaction_send (BusTransaction *transaction,
644 d = BUS_CONNECTION_DATA (connection);
645 _dbus_assert (d != NULL);
648 + if (!deferred_dispatch && d->deferred_messages != NULL)
650 + BusDeferredMessage *deferred_message;
651 + dbus_bool_t success;
652 + /* sender and addressed recipient are not required at this point as we only need to send message
653 + * to a single recipient without performing policy check. */
654 + deferred_message = bus_deferred_message_new (message,
659 + if (deferred_message == NULL)
662 + success = bus_deferred_message_queue_at_recipient(deferred_message, transaction,
664 + bus_deferred_message_unref(deferred_message);
669 to_send = dbus_new (MessageToSend, 1);
672 @@ -2663,6 +2693,131 @@ bus_transaction_add_cancel_hook (BusTransaction *transaction,
677 +bus_connection_dispatch_deferred (DBusConnection *connection)
679 + BusDeferredMessage *message;
681 + _dbus_return_if_fail (connection != NULL);
683 + while ((message = bus_connection_pop_deferred_message(connection)) != NULL)
685 + bus_deferred_message_dispatch(message);
686 + bus_deferred_message_unref(message);
691 +bus_connection_has_deferred_messages (DBusConnection *connection)
693 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
694 + return d->deferred_messages != NULL ? TRUE : FALSE;
698 +bus_connection_queue_deferred_message (DBusConnection *connection,
699 + BusDeferredMessage *message,
700 + dbus_bool_t prepend)
702 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
703 + dbus_bool_t success;
705 + success = _dbus_list_prepend(&d->deferred_messages, message);
707 + success = _dbus_list_append(&d->deferred_messages, message);
711 + bus_deferred_message_ref(message);
719 +bus_connection_replace_deferred_message (DBusConnection *connection,
720 + BusDeferredMessage *oldMessage,
721 + BusDeferredMessage *newMessage)
724 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
726 + link = _dbus_list_find_first(&d->deferred_messages, oldMessage);
730 + if (!_dbus_list_insert_after(&d->deferred_messages, link, newMessage))
733 + bus_deferred_message_ref(newMessage);
734 + _dbus_list_remove_link(&d->deferred_messages, link);
735 + bus_deferred_message_unref(oldMessage);
739 +BusDeferredMessage *
740 +bus_connection_pop_deferred_message (DBusConnection *connection)
743 + BusDeferredMessage *message;
744 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
746 + link =_dbus_list_get_first_link(&d->deferred_messages);
749 + message = link->data;
750 + if (!bus_deferred_message_waits_for_check(message))
752 + _dbus_list_remove_link(&d->deferred_messages, link);
761 +bus_connection_putback_deferred_message (DBusConnection *connection, BusDeferredMessage *message)
763 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
764 + if (_dbus_list_prepend(&d->deferred_messages, message))
772 +bus_connection_clear_deferred_messages (DBusConnection *connection)
774 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
777 + BusDeferredMessage *message;
779 + link =_dbus_list_get_first_link(&d->deferred_messages);
780 + while (link != NULL)
782 + next = _dbus_list_get_next_link (&d->deferred_messages, link);
783 + message = link->data;
785 + bus_deferred_message_unref(message);
786 + _dbus_list_remove_link(&d->deferred_messages, link);
793 +bus_connection_remove_deferred_message (DBusConnection *connection,
794 + BusDeferredMessage *message)
796 + BusConnectionData *d = BUS_CONNECTION_DATA(connection);
797 + if (_dbus_list_remove(&d->deferred_messages, message))
798 + bus_deferred_message_unref(message);
802 bus_connections_get_n_active (BusConnections *connections)
804 diff --git a/bus/connection.h b/bus/connection.h
805 index a6e5dfde..46e883e6 100644
806 --- a/bus/connection.h
807 +++ b/bus/connection.h
808 @@ -83,6 +83,22 @@ dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection);
809 void bus_connection_send_oom_error (DBusConnection *connection,
810 DBusMessage *in_reply_to);
812 +dbus_bool_t bus_connection_has_deferred_messages (DBusConnection *connection);
813 +dbus_bool_t bus_connection_queue_deferred_message (DBusConnection *connection,
814 + BusDeferredMessage *message,
815 + dbus_bool_t prepend);
816 +BusDeferredMessage *bus_connection_pop_deferred_message (DBusConnection *connection);
817 +dbus_bool_t bus_connection_putback_deferred_message (DBusConnection *connection,
818 + BusDeferredMessage *message);
819 +void bus_connection_remove_deferred_message (DBusConnection *connection,
820 + BusDeferredMessage *message);
821 +dbus_bool_t bus_connection_replace_deferred_message (DBusConnection *connection,
822 + BusDeferredMessage *oldMessage,
823 + BusDeferredMessage *newMessage);
824 +void bus_connection_dispatch_deferred (DBusConnection *connection);
825 +void bus_connection_clear_deferred_messages (DBusConnection *connection);
828 /* called by signals.c */
829 dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection,
831 @@ -135,7 +151,8 @@ BusTransaction* bus_transaction_new (BusContext *
832 BusContext* bus_transaction_get_context (BusTransaction *transaction);
833 dbus_bool_t bus_transaction_send (BusTransaction *transaction,
834 DBusConnection *connection,
835 - DBusMessage *message);
836 + DBusMessage *message,
837 + dbus_bool_t deferred_dispatch);
838 dbus_bool_t bus_transaction_capture (BusTransaction *transaction,
839 DBusConnection *connection,
840 DBusMessage *message);
841 diff --git a/bus/dispatch.c b/bus/dispatch.c
842 index 7353501b..e32c9263 100644
849 +#include "dispatch.h"
851 #include <dbus/dbus-internals.h>
852 #include <dbus/dbus-connection-internal.h>
853 @@ -76,7 +77,7 @@ send_one_message (DBusConnection *connection,
857 - if (result != BUS_RESULT_TRUE)
858 + if (result == BUS_RESULT_FALSE)
860 if (!bus_transaction_capture_error_reply (transaction, &stack_error,
862 @@ -111,9 +112,19 @@ send_one_message (DBusConnection *connection,
863 return TRUE; /* don't send it but don't return an error either */
866 + if (result == BUS_RESULT_LATER)
868 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
870 + BUS_SET_OOM (error);
873 + return TRUE; /* pretend to have sent it */
876 if (!bus_transaction_send (transaction,
883 @@ -123,11 +134,12 @@ send_one_message (DBusConnection *connection,
887 -bus_dispatch_matches (BusTransaction *transaction,
888 - DBusConnection *sender,
889 - DBusConnection *addressed_recipient,
890 - DBusMessage *message,
892 +bus_dispatch_matches (BusTransaction *transaction,
893 + DBusConnection *sender,
894 + DBusConnection *addressed_recipient,
895 + DBusMessage *message,
896 + BusDeferredMessage *dispatched_deferred_message,
900 BusConnections *connections;
901 @@ -151,17 +163,78 @@ bus_dispatch_matches (BusTransaction *transaction,
902 /* First, send the message to the addressed_recipient, if there is one. */
903 if (addressed_recipient != NULL)
906 - res = bus_context_check_security_policy (context, transaction,
907 - sender, addressed_recipient,
908 - addressed_recipient,
910 - &deferred_message);
911 - if (res == BUS_RESULT_FALSE)
913 + /* To maintain message order message needs to be appended at the recipient if there are already
914 + * deferred messages and we are not doing deferred dispatch
916 + if (dispatched_deferred_message == NULL && bus_connection_has_deferred_messages(addressed_recipient))
918 + deferred_message = bus_deferred_message_new(message, sender,
919 + addressed_recipient, addressed_recipient, BUS_RESULT_LATER);
921 + if (deferred_message == NULL)
923 + BUS_SET_OOM(error);
924 + return BUS_RESULT_FALSE;
927 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
929 + bus_deferred_message_unref(deferred_message);
930 + BUS_SET_OOM(error);
931 + return BUS_RESULT_FALSE;
934 + bus_deferred_message_unref(deferred_message);
935 + return BUS_RESULT_TRUE; /* pretend to have sent it */
938 + if (dispatched_deferred_message != NULL)
940 + result = bus_deferred_message_get_response(dispatched_deferred_message);
941 + if (result == BUS_RESULT_TRUE)
943 + /* if we know the result of policy check we still need to check if message limits
944 + * are not exceeded. It is also required to add entry in expected replies list if
945 + * this is a method call
947 + if (!bus_deferred_message_check_message_limits(dispatched_deferred_message, error))
948 + return BUS_RESULT_FALSE;
950 + if (!bus_deferred_message_expect_method_reply(dispatched_deferred_message, transaction, error))
951 + return BUS_RESULT_FALSE;
953 + else if (result == BUS_RESULT_FALSE)
955 + bus_deferred_message_create_error(dispatched_deferred_message, "Rejected message", error);
956 + return BUS_RESULT_FALSE;
960 + result = BUS_RESULT_LATER;
962 + if (result == BUS_RESULT_LATER)
963 + result = bus_context_check_security_policy(context, transaction,
964 + sender, addressed_recipient, addressed_recipient, message, error,
965 + &deferred_message);
967 + if (result == BUS_RESULT_FALSE)
968 return BUS_RESULT_FALSE;
969 - else if (res == BUS_RESULT_LATER)
970 + else if (result == BUS_RESULT_LATER)
972 BusDeferredMessageStatus status;
974 + if (dispatched_deferred_message != NULL)
976 + /* for deferred dispatch prepend message at the recipient */
977 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, TRUE))
979 + BUS_SET_OOM(error);
980 + return BUS_RESULT_FALSE;
982 + return BUS_RESULT_TRUE; /* pretend to have sent it */
985 status = bus_deferred_message_get_status(deferred_message);
987 if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
988 @@ -172,13 +245,18 @@ bus_dispatch_matches (BusTransaction *transaction,
990 else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
992 - dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
993 - "Rejecting message because time is needed to check security policy");
994 - return BUS_RESULT_FALSE;
995 + /* receive rule result not available - queue message at the recipient */
996 + if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
998 + BUS_SET_OOM(error);
999 + return BUS_RESULT_FALSE;
1002 + return BUS_RESULT_TRUE; /* pretend to have sent it */
1006 - _dbus_verbose("deferred message has no status field set to send or receive unexpectedly\n");
1007 + _dbus_verbose("deferred message has no status field set unexpectedly\n");
1008 return BUS_RESULT_FALSE;
1011 @@ -195,7 +273,8 @@ bus_dispatch_matches (BusTransaction *transaction,
1014 /* Dispatch the message */
1015 - if (!bus_transaction_send (transaction, addressed_recipient, message))
1016 + if (!bus_transaction_send(transaction, addressed_recipient, message,
1017 + dispatched_deferred_message != NULL ? TRUE : FALSE))
1019 BUS_SET_OOM (error);
1020 return BUS_RESULT_FALSE;
1021 @@ -495,7 +574,7 @@ bus_dispatch (DBusConnection *connection,
1024 if (BUS_RESULT_LATER == bus_dispatch_matches (transaction, connection, addressed_recipient,
1026 + message, NULL, &error))
1028 /* Roll back and dispatch the message once the policy result is available */
1029 bus_transaction_cancel_and_free (transaction);
1030 diff --git a/bus/dispatch.h b/bus/dispatch.h
1031 index afba6a24..f6102e80 100644
1032 --- a/bus/dispatch.h
1033 +++ b/bus/dispatch.h
1036 dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection);
1037 void bus_dispatch_remove_connection (DBusConnection *connection);
1038 -BusResult bus_dispatch_matches (BusTransaction *transaction,
1039 - DBusConnection *sender,
1040 - DBusConnection *recipient,
1041 - DBusMessage *message,
1042 - DBusError *error);
1043 +BusResult bus_dispatch_matches (BusTransaction *transaction,
1044 + DBusConnection *sender,
1045 + DBusConnection *recipient,
1046 + DBusMessage *message,
1047 + BusDeferredMessage *dispatched_deferred_message,
1048 + DBusError *error);
1050 #endif /* BUS_DISPATCH_H */
1051 diff --git a/bus/driver.c b/bus/driver.c
1052 index a5823d4d..5acdd62a 100644
1055 @@ -261,7 +261,7 @@ bus_driver_send_service_owner_changed (const char *service_name,
1056 if (!bus_transaction_capture (transaction, NULL, message))
1059 - res = bus_dispatch_matches (transaction, NULL, NULL, message, error);
1060 + res = bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error);
1061 if (res == BUS_RESULT_TRUE)
1064 diff --git a/bus/policy.c b/bus/policy.c
1065 index bcade176..47bd1a24 100644
1068 @@ -1071,6 +1071,9 @@ bus_client_policy_check_can_send (DBusConnection *sender,
1070 result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
1071 privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
1072 + if (result == BUS_RESULT_LATER && deferred_message != NULL)
1073 + bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
1074 + *toggles, privilege);
1078 @@ -1305,6 +1308,9 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1080 result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
1081 privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
1082 + if (result == BUS_RESULT_LATER && deferred_message != NULL)
1083 + bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
1084 + *toggles, privilege);