Upgrade to thud
[AGL/meta-agl.git] / meta-security / recipes-core / dbus-cynara / dbus-cynara / 0003-Handle-unavailability-of-policy-results-for-broadcas.patch
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
5  and receive rules
6 MIME-Version: 1.0
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
9
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.
21
22 Change-Id: Iecd5395f75a4c7811fa97247a37d8fc4d42e8814
23
24 Cherry picked from 1e231194610892dd4360224998d91336097b05a1 by Jose Bollo
25
26 Updated for dbus 1.12.10 by Scott Murray.
27
28 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
29 Signed-off-by: Scott Murray <scott.murray@konsulko.com>
30
31 diff --git a/bus/activation.c b/bus/activation.c
32 index 5f02153..f2981e1 100644
33 --- a/bus/activation.c
34 +++ b/bus/activation.c
35 @@ -1259,7 +1259,7 @@ bus_activation_send_pending_auto_activation_messages (BusActivation  *activation
36            res = bus_dispatch_matches (transaction,
37                                        entry->connection,
38                                        addressed_recipient,
39 -                                      entry->activation_message, &error);
40 +                                      entry->activation_message, NULL, &error);
41            if (res == BUS_RESULT_FALSE)
42              {
43                /* If permission is denied, we just want to return the error
44 @@ -2137,7 +2137,7 @@ bus_activation_activate_service (BusActivation  *activation,
45                                 bus_connection_get_loginfo (connection));
46                /* Wonderful, systemd is connected, let's just send the msg */
47                res = bus_dispatch_matches (activation_transaction, NULL,
48 -                                          systemd, message, error);
49 +                                          systemd, message, NULL, error);
50  
51                if (res == BUS_RESULT_TRUE)
52                  retval = TRUE;
53 diff --git a/bus/bus.c b/bus/bus.c
54 index 237efe3..5bb5637 100644
55 --- a/bus/bus.c
56 +++ b/bus/bus.c
57 @@ -1800,17 +1800,9 @@ bus_context_check_security_policy (BusContext     *context,
58      }
59  
60    /* See if limits on size have been exceeded */
61 -  if (proposed_recipient &&
62 -      ((dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) ||
63 -       (dbus_connection_get_outgoing_unix_fds (proposed_recipient) > context->limits.max_outgoing_unix_fds)))
64 -    {
65 -      complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
66 -          "Rejected: destination has a full message queue",
67 -          0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
68 -          error);
69 -      _dbus_verbose ("security policy disallowing message due to full message queue\n");
70 +  if (!bus_context_check_recipient_message_limits(context, proposed_recipient, sender, message,
71 +      requested_reply, error))
72        return BUS_RESULT_FALSE;
73 -    }
74  
75    /* Record that we will allow a reply here in the future (don't
76     * bother if the recipient is the bus or this is an eavesdropping
77 @@ -1869,3 +1861,41 @@ bus_context_check_all_watches (BusContext *context)
78        _dbus_server_toggle_all_watches (server, enabled);
79      }
80  }
81 +
82 +void
83 +bus_context_complain_about_message (BusContext     *context,
84 +                                    const char     *error_name,
85 +                                    const char     *complaint,
86 +                                    int             matched_rules,
87 +                                    DBusMessage    *message,
88 +                                    DBusConnection *sender,
89 +                                    DBusConnection *proposed_recipient,
90 +                                    dbus_bool_t     requested_reply,
91 +                                    dbus_bool_t     log,
92 +                                    const char     *privilege,
93 +                                    DBusError      *error)
94 +{
95 +  complain_about_message(context, error_name, complaint, matched_rules, message, sender,
96 +      proposed_recipient, requested_reply, log, privilege, error);
97 +}
98 +
99 +dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
100 +                                                        DBusConnection *recipient,
101 +                                                        DBusConnection *sender,
102 +                                                        DBusMessage *message,
103 +                                                        dbus_bool_t requested_reply,
104 +                                                        DBusError *error)
105 +{
106 +  if (recipient &&
107 +       ((dbus_connection_get_outgoing_size (recipient) > context->limits.max_outgoing_bytes) ||
108 +        (dbus_connection_get_outgoing_unix_fds (recipient) > context->limits.max_outgoing_unix_fds)))
109 +     {
110 +       complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
111 +           "Rejected: destination has a full message queue",
112 +           0, message, sender, recipient, requested_reply, TRUE, NULL,
113 +           error);
114 +       _dbus_verbose ("security policy disallowing message due to full message queue\n");
115 +       return FALSE;
116 +     }
117 +  return TRUE;
118 +}
119 diff --git a/bus/bus.h b/bus/bus.h
120 index 82c32c8..1b08f7c 100644
121 --- a/bus/bus.h
122 +++ b/bus/bus.h
123 @@ -164,4 +164,23 @@ BusResult         bus_context_check_security_policy              (BusContext
124                                                                    BusDeferredMessage **deferred_message);
125  void              bus_context_check_all_watches                  (BusContext       *context);
126  
127 +dbus_bool_t       bus_context_check_recipient_message_limits     (BusContext *context,
128 +                                                                  DBusConnection *recipient,
129 +                                                                  DBusConnection *sender,
130 +                                                                  DBusMessage *message,
131 +                                                                  dbus_bool_t requested_reply,
132 +                                                                  DBusError *error);
133 +void              bus_context_complain_about_message             (BusContext     *context,
134 +                                                                  const char     *error_name,
135 +                                                                  const char     *complaint,
136 +                                                                  int             matched_rules,
137 +                                                                  DBusMessage    *message,
138 +                                                                  DBusConnection *sender,
139 +                                                                  DBusConnection *proposed_recipient,
140 +                                                                  dbus_bool_t     requested_reply,
141 +                                                                  dbus_bool_t     log,
142 +                                                                  const char     *privilege,
143 +                                                                  DBusError      *error);
144 +
145 +
146  #endif /* BUS_BUS_H */
147 diff --git a/bus/check.c b/bus/check.c
148 index 4b8a699..f3d283f 100644
149 --- a/bus/check.c
150 +++ b/bus/check.c
151 @@ -49,6 +49,9 @@ typedef struct BusDeferredMessage
152    DBusConnection *sender;
153    DBusConnection *proposed_recipient;
154    DBusConnection *addressed_recipient;
155 +  dbus_bool_t requested_reply;
156 +  int matched_rules;
157 +  const char *privilege;
158    dbus_bool_t full_dispatch;
159    BusDeferredMessageStatus status;
160    BusResult response;
161 @@ -135,6 +138,89 @@ bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
162    _dbus_connection_enable_dispatch(deferred_message->sender);
163  }
164  
165 +static void
166 +bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
167 +                                         BusResult result)
168 +{
169 +  int status;
170 +
171 +  _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
172 +
173 +  if (!bus_connection_is_active(deferred_message->proposed_recipient))
174 +    return;
175 +
176 +  status = deferred_message->status;
177 +
178 +  deferred_message->status = 0; /* mark message as not waiting for response */
179 +  deferred_message->response = result;
180 +
181 +  /*
182 +   * If send rule allows us to send message we still need to check receive rules.
183 +   */
184 +  if ((status & BUS_DEFERRED_MESSAGE_CHECK_SEND) && (result == BUS_RESULT_TRUE))
185 +    {
186 +      int toggles;
187 +      BusContext *context;
188 +      BusRegistry *registry;
189 +      BusClientPolicy *recipient_policy;
190 +      BusDeferredMessage *deferred_message_receive;
191 +
192 +      context = bus_connection_get_context(deferred_message->proposed_recipient);
193 +      registry = bus_context_get_registry(context);
194 +      recipient_policy = bus_connection_get_policy(deferred_message->proposed_recipient);
195 +
196 +      deferred_message->response = bus_client_policy_check_can_receive(recipient_policy, registry,
197 +          deferred_message->requested_reply, deferred_message->sender,
198 +          deferred_message->addressed_recipient, deferred_message->proposed_recipient, deferred_message->message,
199 +          &toggles, NULL, &deferred_message_receive);
200 +      if (deferred_message->response == BUS_RESULT_LATER)
201 +        {
202 +          /* replace deferred message associated with send check with the one associated with
203 +           * receive check */
204 +          if (!bus_deferred_message_replace(deferred_message, deferred_message_receive))
205 +            {
206 +              /* failed to replace deferred message (due to oom). Set it to rejected */
207 +              deferred_message->response = BUS_RESULT_FALSE;
208 +            }
209 +        }
210 +    }
211 +
212 +  bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
213 +}
214 +
215 +static void
216 +queue_deferred_message_cancel_transaction_hook (void *data)
217 +{
218 +  BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
219 +  bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
220 +}
221 +
222 +
223 +dbus_bool_t
224 +bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
225 +                                         BusTransaction *transaction,
226 +                                         dbus_bool_t full_dispatch,
227 +                                         dbus_bool_t prepend)
228 +{
229 +  _dbus_assert(deferred_message != NULL);
230 +  _dbus_assert(deferred_message->proposed_recipient != NULL);
231 +
232 +  if (!bus_connection_queue_deferred_message(deferred_message->proposed_recipient,
233 +         deferred_message, prepend))
234 +    return FALSE;
235 +
236 +  if (!bus_transaction_add_cancel_hook(transaction, queue_deferred_message_cancel_transaction_hook,
237 +      deferred_message, NULL))
238 +    {
239 +      bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
240 +      return FALSE;
241 +    }
242 +  deferred_message->response_callback = bus_check_queued_message_reply_callback;
243 +  deferred_message->full_dispatch = full_dispatch;
244 +
245 +  return TRUE;
246 +}
247 +
248  static void
249  deferred_message_free_function(void *data)
250  {
251 @@ -159,6 +245,20 @@ bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
252    deferred_message->response_callback = bus_check_enable_dispatch_callback;
253  }
254  
255 +void
256 +bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
257 +                                            dbus_bool_t requested_reply,
258 +                                            int matched_rules,
259 +                                            const char *privilege)
260 +{
261 +  _dbus_assert(deferred_message != NULL);
262 +
263 +  deferred_message->requested_reply = requested_reply;
264 +  deferred_message->matched_rules = matched_rules;
265 +  deferred_message->privilege = privilege;
266 +}
267 +
268 +
269  #ifdef DBUS_ENABLE_EMBEDDED_TESTS
270  BusResult (*bus_check_test_override) (DBusConnection *connection,
271                                          const char *privilege);
272 @@ -259,6 +359,9 @@ BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
273    deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
274    deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
275    deferred_message->message = dbus_message_ref(message);
276 +  deferred_message->requested_reply = FALSE;
277 +  deferred_message->matched_rules = 0;
278 +  deferred_message->privilege = NULL;
279    deferred_message->response = response;
280    deferred_message->status = 0;
281    deferred_message->full_dispatch = FALSE;
282 @@ -295,12 +398,215 @@ bus_deferred_message_unref (BusDeferredMessage *deferred_message)
283       }
284  }
285  
286 +dbus_bool_t
287 +bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message, DBusError *error)
288 +{
289 +  BusContext *context = bus_connection_get_context(deferred_message->proposed_recipient);
290 +
291 +  return bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
292 +      deferred_message->sender, deferred_message->message, deferred_message->requested_reply,
293 +      error);
294 +}
295 +
296 +dbus_bool_t
297 +bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, BusTransaction *transaction, DBusError *error)
298 +{
299 +  int type = dbus_message_get_type(deferred_message->message);
300 +  if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
301 +        deferred_message->sender &&
302 +        deferred_message->addressed_recipient &&
303 +        deferred_message->addressed_recipient == deferred_message->proposed_recipient && /* not eavesdropping */
304 +        !bus_connections_expect_reply (bus_connection_get_connections (deferred_message->sender),
305 +                                       transaction,
306 +                                       deferred_message->sender, deferred_message->addressed_recipient,
307 +                                       deferred_message->message, error))
308 +    {
309 +      _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
310 +      return FALSE;
311 +    }
312 +  return TRUE;
313 +}
314 +
315 +void
316 +bus_deferred_message_create_error(BusDeferredMessage *deferred_message,
317 +    const char *error_message, DBusError *error)
318 +{
319 +  BusContext *context;
320 +  _dbus_assert (deferred_message->status == 0 && deferred_message->response == BUS_RESULT_FALSE);
321 +
322 +  if (deferred_message->sender == NULL)
323 +    return; /* error won't be sent to bus driver anyway */
324 +
325 +  context = bus_connection_get_context(deferred_message->sender);
326 +  bus_context_complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected message",
327 +      deferred_message->matched_rules, deferred_message->message, deferred_message->sender,
328 +      deferred_message->proposed_recipient, deferred_message->requested_reply, FALSE,
329 +      deferred_message->privilege, error);
330 +}
331 +
332 +BusResult
333 +bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
334 +{
335 +  BusContext *context = bus_connection_get_context (deferred_message->proposed_recipient);
336 +  BusTransaction *transaction = bus_transaction_new (context);
337 +  BusResult result = BUS_RESULT_TRUE;
338 +  DBusError error;
339 +
340 +  if (transaction == NULL)
341 +    {
342 +      return BUS_RESULT_FALSE;
343 +    }
344 +
345 +  dbus_error_init(&error);
346 +
347 +  if (!deferred_message->full_dispatch)
348 +    {
349 +      result = deferred_message->response;
350 +      if (result == BUS_RESULT_TRUE)
351 +        {
352 +          if (!bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
353 +               deferred_message->sender, deferred_message->message, deferred_message->requested_reply, &error))
354 +              result = BUS_RESULT_FALSE;
355 +        }
356 +      else if (result == BUS_RESULT_LATER)
357 +        {
358 +          BusDeferredMessage *deferred_message2;
359 +          result = bus_context_check_security_policy (context, transaction,
360 +                                                      deferred_message->sender,
361 +                                                      deferred_message->addressed_recipient,
362 +                                                      deferred_message->proposed_recipient,
363 +                                                      deferred_message->message, NULL, NULL,
364 +                                                      &deferred_message2);
365 +
366 +          if (result == BUS_RESULT_LATER)
367 +            {
368 +              /* prepend at recipient */
369 +              if (!bus_deferred_message_queue_at_recipient(deferred_message2, transaction,
370 +                  FALSE, TRUE))
371 +                result = BUS_RESULT_FALSE;
372 +            }
373 +        }
374 +
375 +      /* silently drop messages on access denial */
376 +      if (result == BUS_RESULT_TRUE)
377 +        {
378 +          if (!bus_transaction_send (transaction, deferred_message->proposed_recipient, deferred_message->message, TRUE))
379 +            result = BUS_RESULT_FALSE;
380 +        }
381 +
382 +      bus_transaction_execute_and_free(transaction);
383 +
384 +      goto out;
385 +    }
386 +
387 +  /* do not attempt to send message if sender has disconnected */
388 +  if (deferred_message->sender != NULL && !bus_connection_is_active(deferred_message->sender))
389 +    {
390 +      bus_transaction_cancel_and_free(transaction);
391 +      result = BUS_RESULT_FALSE;
392 +      goto out;
393 +    }
394 +
395 +  result = bus_dispatch_matches(transaction, deferred_message->sender,
396 +      deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
397 +
398 +  if (result == BUS_RESULT_LATER)
399 +    {
400 +      /* Message deferring was already done in bus_dispatch_matches */
401 +      bus_transaction_cancel_and_free(transaction);
402 +      goto out;
403 +    }
404 +
405 +  /* this part is a copy & paste from bus_dispatch function. Probably can be moved to a function */
406 +  if (dbus_error_is_set (&error))
407 +    {
408 +      if (!dbus_connection_get_is_connected (deferred_message->sender))
409 +        {
410 +          /* If we disconnected it, we won't bother to send it any error
411 +           * messages.
412 +           */
413 +          _dbus_verbose ("Not sending error to connection we disconnected\n");
414 +        }
415 +      else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
416 +        {
417 +          bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
418 +
419 +          /* cancel transaction due to OOM */
420 +          if (transaction != NULL)
421 +            {
422 +              bus_transaction_cancel_and_free (transaction);
423 +              transaction = NULL;
424 +            }
425 +        }
426 +      else
427 +        {
428 +          /* Try to send the real error, if no mem to do that, send
429 +           * the OOM error
430 +           */
431 +          _dbus_assert (transaction != NULL);
432 +          if (!bus_transaction_send_error_reply (transaction, deferred_message->sender,
433 +                                                 &error, deferred_message->message))
434 +            {
435 +              bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
436 +
437 +              /* cancel transaction due to OOM */
438 +              if (transaction != NULL)
439 +                {
440 +                  bus_transaction_cancel_and_free (transaction);
441 +                  transaction = NULL;
442 +                }
443 +            }
444 +        }
445 +    }
446 +
447 +  if (transaction != NULL)
448 +    {
449 +      bus_transaction_execute_and_free (transaction);
450 +    }
451 +
452 +out:
453 +  dbus_error_free(&error);
454 +
455 +  return result;
456 +}
457 +
458 +dbus_bool_t
459 +bus_deferred_message_replace (BusDeferredMessage *old_message, BusDeferredMessage *new_message)
460 +{
461 +  if (bus_connection_replace_deferred_message(old_message->proposed_recipient,
462 +        old_message, new_message))
463 +    {
464 +      new_message->response_callback = old_message->response_callback;
465 +      new_message->full_dispatch = old_message->full_dispatch;
466 +      return TRUE;
467 +    }
468 +  return FALSE;
469 +}
470 +
471 +dbus_bool_t
472 +bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
473 +{
474 +  return deferred_message->status != 0;
475 +}
476 +
477 +DBusConnection *
478 +bus_deferred_message_get_recipient(BusDeferredMessage *deferred_message)
479 +{
480 +  return deferred_message->proposed_recipient;
481 +}
482 +
483  BusDeferredMessageStatus
484  bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
485  {
486    return deferred_message->status;
487  }
488  
489 +BusResult
490 +bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
491 +{
492 +  return deferred_message->response;
493 +}
494 +
495  void
496  bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
497                                          BusResult result)
498 @@ -310,3 +616,4 @@ bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
499        deferred_message->response_callback(deferred_message, result);
500      }
501  }
502 +
503 diff --git a/bus/check.h b/bus/check.h
504 index d177549..9c13c18 100644
505 --- a/bus/check.h
506 +++ b/bus/check.h
507 @@ -64,12 +64,37 @@ BusDeferredMessage *bus_deferred_message_new                (DBusMessage *messag
508  
509  BusDeferredMessage *bus_deferred_message_ref                (BusDeferredMessage *deferred_message);
510  void                bus_deferred_message_unref              (BusDeferredMessage *deferred_message);
511 +BusResult           bus_deferred_message_dispatch           (BusDeferredMessage *deferred_message);
512 +dbus_bool_t         bus_deferred_message_waits_for_check    (BusDeferredMessage *deferred_message);
513 +DBusConnection     *bus_deferred_message_get_recipient      (BusDeferredMessage *deferred_message);
514  void                bus_deferred_message_response_received  (BusDeferredMessage *deferred_message,
515                                                               BusResult result);
516 +dbus_bool_t         bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
517 +                                                             BusTransaction *transaction,
518 +                                                             dbus_bool_t full_dispatch,
519 +                                                             dbus_bool_t prepend);
520 +dbus_bool_t         bus_deferred_message_replace            (BusDeferredMessage *old_message,
521 +                                                             BusDeferredMessage *new_message);
522  void                bus_deferred_message_disable_sender     (BusDeferredMessage *deferred_message);
523 +BusResult           bus_deferred_message_get_response       (BusDeferredMessage *deferred_message);
524  
525  BusDeferredMessageStatus  bus_deferred_message_get_status   (BusDeferredMessage *deferred_message);
526  
527 +
528 +dbus_bool_t         bus_deferred_message_expect_method_reply (BusDeferredMessage *deferred_message,
529 +                                                              BusTransaction *transaction,
530 +                                                              DBusError *error);
531 +void                bus_deferred_message_create_error        (BusDeferredMessage *deferred_message,
532 +                                                              const char *error_message,
533 +                                                              DBusError *error);
534 +void                bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
535 +                                                                dbus_bool_t requested_reply,
536 +                                                                int matched_rules,
537 +                                                                const char *privilege);
538 +dbus_bool_t         bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message,
539 +                                                               DBusError *error);
540 +
541 +
542  #ifdef DBUS_ENABLE_EMBEDDED_TESTS
543  extern BusResult (*bus_check_test_override) (DBusConnection *connection,
544                                                 const char *privilege);
545 diff --git a/bus/connection.c b/bus/connection.c
546 index deebde3..f9e563b 100644
547 --- a/bus/connection.c
548 +++ b/bus/connection.c
549 @@ -31,11 +31,13 @@
550  #include "expirelist.h"
551  #include "selinux.h"
552  #include "apparmor.h"
553 +#include "check.h"
554  #include <dbus/dbus-list.h>
555  #include <dbus/dbus-hash.h>
556  #include <dbus/dbus-timeout.h>
557  #include <dbus/dbus-connection-internal.h>
558  #include <dbus/dbus-internals.h>
559 +#include <dbus/dbus-message-internal.h>
560  #ifdef DBUS_ENABLE_CYNARA
561  #include <stdlib.h>
562  #include <cynara-session.h>
563 @@ -102,6 +104,7 @@ typedef struct
564    DBusMessage *oom_message;
565    DBusPreallocatedSend *oom_preallocated;
566    BusClientPolicy *policy;
567 +  DBusList *deferred_messages;  /**< Queue of messages deferred due to pending policy check */
568  
569    char *cached_loginfo_string;
570    BusSELinuxID *selinux_id;
571 @@ -268,6 +271,8 @@ bus_connection_disconnected (DBusConnection *connection)
572        bus_transaction_execute_and_free (transaction);
573      }
574  
575 +  bus_connection_clear_deferred_messages(connection);
576 +
577    bus_dispatch_remove_connection (connection);
578    
579    /* no more watching */
580 @@ -2307,7 +2312,7 @@ bus_transaction_capture (BusTransaction *transaction,
581      {
582        DBusConnection *recipient = link->data;
583  
584 -      if (!bus_transaction_send (transaction, recipient, message))
585 +      if (!bus_transaction_send (transaction, recipient, message, FALSE))
586          goto out;
587      }
588  
589 @@ -2361,6 +2366,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
590  {
591    DBusError error = DBUS_ERROR_INIT;
592    BusResult res;
593 +  BusDeferredMessage *deferred_message;
594  
595    /* We have to set the sender to the driver, and have
596     * to check security policy since it was not done in
597 @@ -2402,7 +2408,8 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
598                                             transaction,
599                                             NULL, connection, connection,
600                                             message, NULL, &error,
601 -                                           NULL);
602 +                                           &deferred_message);
603 +
604    if (res == BUS_RESULT_FALSE)
605      {
606        if (!bus_transaction_capture_error_reply (transaction, connection,
607 @@ -2420,18 +2427,20 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
608      }
609    else if (res == BUS_RESULT_LATER)
610      {
611 -      _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
612        dbus_error_free (&error);
613 -      return TRUE;
614 +      if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
615 +        return FALSE;
616 +      return TRUE; /* pretend to have sent it */
617      }
618  
619 -  return bus_transaction_send (transaction, connection, message);
620 +  return bus_transaction_send (transaction, connection, message, FALSE);
621  }
622  
623  dbus_bool_t
624  bus_transaction_send (BusTransaction *transaction,
625                        DBusConnection *connection,
626 -                      DBusMessage    *message)
627 +                      DBusMessage    *message,
628 +                      dbus_bool_t     deferred_dispatch)
629  {
630    MessageToSend *to_send;
631    BusConnectionData *d;
632 @@ -2457,7 +2466,28 @@ bus_transaction_send (BusTransaction *transaction,
633    
634    d = BUS_CONNECTION_DATA (connection);
635    _dbus_assert (d != NULL);
636 -  
637 +
638 +  if (!deferred_dispatch && d->deferred_messages != NULL)
639 +    {
640 +      BusDeferredMessage *deferred_message;
641 +      dbus_bool_t success;
642 +      /* sender and addressed recipient are not required at this point as we only need to send message
643 +       * to a single recipient without performing policy check. */
644 +      deferred_message = bus_deferred_message_new (message,
645 +                                                   NULL,
646 +                                                   NULL,
647 +                                                   connection,
648 +                                                   BUS_RESULT_TRUE);
649 +      if (deferred_message == NULL)
650 +        return FALSE;
651 +
652 +      success = bus_deferred_message_queue_at_recipient(deferred_message, transaction,
653 +          FALSE, FALSE);
654 +      bus_deferred_message_unref(deferred_message);
655 +
656 +      return success;
657 +    }
658 +
659    to_send = dbus_new (MessageToSend, 1);
660    if (to_send == NULL)
661      {
662 @@ -2709,6 +2739,131 @@ bus_transaction_add_cancel_hook (BusTransaction               *transaction,
663    return TRUE;
664  }
665  
666 +void
667 +bus_connection_dispatch_deferred (DBusConnection *connection)
668 +{
669 +  BusDeferredMessage *message;
670 +
671 +  _dbus_return_if_fail (connection != NULL);
672 +
673 +  while ((message = bus_connection_pop_deferred_message(connection)) != NULL)
674 +    {
675 +      bus_deferred_message_dispatch(message);
676 +      bus_deferred_message_unref(message);
677 +    }
678 +}
679 +
680 +dbus_bool_t
681 +bus_connection_has_deferred_messages (DBusConnection *connection)
682 +{
683 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
684 +  return d->deferred_messages != NULL ? TRUE : FALSE;
685 +}
686 +
687 +dbus_bool_t
688 +bus_connection_queue_deferred_message (DBusConnection *connection,
689 +                                       BusDeferredMessage *message,
690 +                                       dbus_bool_t prepend)
691 +{
692 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
693 +  dbus_bool_t success;
694 +  if (prepend)
695 +    success = _dbus_list_prepend(&d->deferred_messages, message);
696 +  else
697 +    success = _dbus_list_append(&d->deferred_messages, message);
698 +
699 +  if (success)
700 +    {
701 +      bus_deferred_message_ref(message);
702 +      return TRUE;
703 +    }
704 +
705 +  return FALSE;
706 +}
707 +
708 +dbus_bool_t
709 +bus_connection_replace_deferred_message (DBusConnection *connection,
710 +                                         BusDeferredMessage *oldMessage,
711 +                                         BusDeferredMessage *newMessage)
712 +{
713 +  DBusList *link;
714 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
715 +
716 +  link = _dbus_list_find_first(&d->deferred_messages, oldMessage);
717 +  if (link == NULL)
718 +    return FALSE;
719 +
720 +  if (!_dbus_list_insert_after(&d->deferred_messages, link, newMessage))
721 +    return FALSE;
722 +
723 +  bus_deferred_message_ref(newMessage);
724 +  _dbus_list_remove_link(&d->deferred_messages, link);
725 +  bus_deferred_message_unref(oldMessage);
726 +  return TRUE;
727 +}
728 +
729 +BusDeferredMessage *
730 +bus_connection_pop_deferred_message (DBusConnection *connection)
731 +{
732 +  DBusList *link;
733 +  BusDeferredMessage *message;
734 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
735 +
736 +  link =_dbus_list_get_first_link(&d->deferred_messages);
737 +  if (link != NULL)
738 +    {
739 +      message = link->data;
740 +      if (!bus_deferred_message_waits_for_check(message))
741 +        {
742 +          _dbus_list_remove_link(&d->deferred_messages, link);
743 +          return message;
744 +        }
745 +    }
746 +
747 +  return NULL;
748 +}
749 +
750 +dbus_bool_t
751 +bus_connection_putback_deferred_message (DBusConnection *connection, BusDeferredMessage *message)
752 +{
753 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
754 +  if (_dbus_list_prepend(&d->deferred_messages, message))
755 +    {
756 +      return TRUE;
757 +    }
758 +  return FALSE;
759 +}
760 +
761 +void
762 +bus_connection_clear_deferred_messages (DBusConnection *connection)
763 +{
764 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
765 +  DBusList *link;
766 +  DBusList *next;
767 +  BusDeferredMessage *message;
768 +
769 +  link =_dbus_list_get_first_link(&d->deferred_messages);
770 +  while (link != NULL)
771 +    {
772 +      next = _dbus_list_get_next_link (&d->deferred_messages, link);
773 +      message = link->data;
774 +
775 +      bus_deferred_message_unref(message);
776 +      _dbus_list_remove_link(&d->deferred_messages, link);
777 +
778 +      link = next;
779 +    }
780 +}
781 +
782 +void
783 +bus_connection_remove_deferred_message (DBusConnection *connection,
784 +                                        BusDeferredMessage *message)
785 +{
786 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
787 +  if (_dbus_list_remove(&d->deferred_messages, message))
788 +    bus_deferred_message_unref(message);
789 +}
790 +
791  int
792  bus_connections_get_n_active (BusConnections *connections)
793  {
794 diff --git a/bus/connection.h b/bus/connection.h
795 index 71078ea..97dae96 100644
796 --- a/bus/connection.h
797 +++ b/bus/connection.h
798 @@ -85,6 +85,22 @@ dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection);
799  void        bus_connection_send_oom_error        (DBusConnection *connection,
800                                                    DBusMessage    *in_reply_to);
801  
802 +dbus_bool_t         bus_connection_has_deferred_messages    (DBusConnection *connection);
803 +dbus_bool_t         bus_connection_queue_deferred_message   (DBusConnection *connection,
804 +                                                             BusDeferredMessage *message,
805 +                                                             dbus_bool_t prepend);
806 +BusDeferredMessage *bus_connection_pop_deferred_message     (DBusConnection *connection);
807 +dbus_bool_t         bus_connection_putback_deferred_message (DBusConnection *connection,
808 +                                                             BusDeferredMessage *message);
809 +void                bus_connection_remove_deferred_message  (DBusConnection *connection,
810 +                                                             BusDeferredMessage *message);
811 +dbus_bool_t         bus_connection_replace_deferred_message (DBusConnection *connection,
812 +                                                             BusDeferredMessage *oldMessage,
813 +                                                             BusDeferredMessage *newMessage);
814 +void                bus_connection_dispatch_deferred        (DBusConnection *connection);
815 +void                bus_connection_clear_deferred_messages  (DBusConnection *connection);
816 +
817 +
818  /* called by signals.c */
819  dbus_bool_t bus_connection_add_match_rule      (DBusConnection *connection,
820                                                  BusMatchRule   *rule);
821 @@ -137,7 +153,8 @@ BusTransaction* bus_transaction_new              (BusContext                   *
822  BusContext*     bus_transaction_get_context      (BusTransaction               *transaction);
823  dbus_bool_t     bus_transaction_send             (BusTransaction               *transaction,
824                                                    DBusConnection               *connection,
825 -                                                  DBusMessage                  *message);
826 +                                                  DBusMessage                  *message,
827 +                                                  dbus_bool_t                   deferred_dispatch);
828  dbus_bool_t     bus_transaction_capture          (BusTransaction               *transaction,
829                                                    DBusConnection               *connection,
830                                                    DBusConnection               *addressed_recipient,
831 diff --git a/bus/dispatch.c b/bus/dispatch.c
832 index 0250b53..1bdcbf0 100644
833 --- a/bus/dispatch.c
834 +++ b/bus/dispatch.c
835 @@ -33,6 +33,7 @@
836  #include "utils.h"
837  #include "bus.h"
838  #include "signals.h"
839 +#include "dispatch.h"
840  #include "test.h"
841  #include <dbus/dbus-internals.h>
842  #include <dbus/dbus-connection-internal.h>
843 @@ -77,7 +78,7 @@ send_one_message (DBusConnection *connection,
844                                            NULL,
845                                            &stack_error,
846                                            &deferred_message);
847 -  if (result != BUS_RESULT_TRUE)
848 +  if (result == BUS_RESULT_FALSE)
849      {
850        if (!bus_transaction_capture_error_reply (transaction, sender,
851                                                  &stack_error, message))
852 @@ -112,9 +113,19 @@ send_one_message (DBusConnection *connection,
853        return TRUE; /* don't send it but don't return an error either */
854      }
855  
856 +  if (result == BUS_RESULT_LATER)
857 +    {
858 +      if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
859 +        {
860 +          BUS_SET_OOM (error);
861 +          return FALSE;
862 +        }
863 +      return TRUE; /* pretend to have sent it */
864 +    }
865 +
866    if (!bus_transaction_send (transaction,
867                               connection,
868 -                             message))
869 +                             message, FALSE))
870      {
871        BUS_SET_OOM (error);
872        return FALSE;
873 @@ -124,11 +135,12 @@ send_one_message (DBusConnection *connection,
874  }
875  
876  BusResult
877 -bus_dispatch_matches (BusTransaction *transaction,
878 -                      DBusConnection *sender,
879 -                      DBusConnection *addressed_recipient,
880 -                      DBusMessage    *message,
881 -                      DBusError      *error)
882 +bus_dispatch_matches (BusTransaction     *transaction,
883 +                      DBusConnection     *sender,
884 +                      DBusConnection     *addressed_recipient,
885 +                      DBusMessage        *message,
886 +                      BusDeferredMessage *dispatched_deferred_message,
887 +                      DBusError          *error)
888  {
889    DBusError tmp_error;
890    BusConnections *connections;
891 @@ -152,17 +164,78 @@ bus_dispatch_matches (BusTransaction *transaction,
892    /* First, send the message to the addressed_recipient, if there is one. */
893    if (addressed_recipient != NULL)
894      {
895 -      BusResult res;
896 -      res = bus_context_check_security_policy (context, transaction,
897 -                                               sender, addressed_recipient,
898 -                                               addressed_recipient,
899 -                                               message, NULL, error,
900 -                                               &deferred_message);
901 -      if (res == BUS_RESULT_FALSE)
902 +      BusResult result;
903 +      /* To maintain message order message needs to be appended at the recipient if there are already
904 +       *  deferred messages and we are not doing deferred dispatch
905 +       */
906 +      if (dispatched_deferred_message == NULL && bus_connection_has_deferred_messages(addressed_recipient))
907 +        {
908 +          deferred_message = bus_deferred_message_new(message, sender,
909 +              addressed_recipient, addressed_recipient, BUS_RESULT_LATER);
910 +
911 +          if (deferred_message == NULL)
912 +            {
913 +              BUS_SET_OOM(error);
914 +              return BUS_RESULT_FALSE;
915 +            }
916 +
917 +          if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
918 +            {
919 +              bus_deferred_message_unref(deferred_message);
920 +              BUS_SET_OOM(error);
921 +              return BUS_RESULT_FALSE;
922 +            }
923 +
924 +          bus_deferred_message_unref(deferred_message);
925 +          return BUS_RESULT_TRUE; /* pretend to have sent it */
926 +        }
927 +
928 +      if (dispatched_deferred_message != NULL)
929 +        {
930 +          result = bus_deferred_message_get_response(dispatched_deferred_message);
931 +          if (result == BUS_RESULT_TRUE)
932 +            {
933 +              /* if we know the result of policy check we still need to check if message limits
934 +               * are not exceeded. It is also required to add entry in expected replies list if
935 +               * this is a method call
936 +               */
937 +              if (!bus_deferred_message_check_message_limits(dispatched_deferred_message, error))
938 +                return BUS_RESULT_FALSE;
939 +
940 +              if (!bus_deferred_message_expect_method_reply(dispatched_deferred_message, transaction, error))
941 +                return BUS_RESULT_FALSE;
942 +            }
943 +          else if (result == BUS_RESULT_FALSE)
944 +            {
945 +              bus_deferred_message_create_error(dispatched_deferred_message, "Rejected message", error);
946 +              return BUS_RESULT_FALSE;
947 +            }
948 +        }
949 +      else
950 +        result = BUS_RESULT_LATER;
951 +
952 +      if (result == BUS_RESULT_LATER)
953 +        result = bus_context_check_security_policy(context, transaction,
954 +            sender, addressed_recipient, addressed_recipient, message, NULL, error,
955 +            &deferred_message);
956 +
957 +      if (result == BUS_RESULT_FALSE)
958          return BUS_RESULT_FALSE;
959 -      else if (res == BUS_RESULT_LATER)
960 +      else if (result == BUS_RESULT_LATER)
961          {
962            BusDeferredMessageStatus status;
963 +
964 +          if (dispatched_deferred_message != NULL)
965 +            {
966 +              /* for deferred dispatch prepend message at the recipient */
967 +              if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, TRUE))
968 +                {
969 +                  BUS_SET_OOM(error);
970 +                  return BUS_RESULT_FALSE;
971 +                }
972 +              return BUS_RESULT_TRUE; /* pretend to have sent it */
973 +            }
974 +
975            status = bus_deferred_message_get_status(deferred_message);
976  
977            if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
978 @@ -173,13 +246,18 @@ bus_dispatch_matches (BusTransaction *transaction,
979              }
980            else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
981              {
982 -              dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
983 -                              "Rejecting message because time is needed to check security policy");
984 -              return BUS_RESULT_FALSE;
985 +              /* receive rule result not available - queue message at the recipient */
986 +              if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
987 +                {
988 +                  BUS_SET_OOM(error);
989 +                  return BUS_RESULT_FALSE;
990 +                }
991 +
992 +              return BUS_RESULT_TRUE; /* pretend to have sent it */
993              }
994            else
995              {
996 -              _dbus_verbose("deferred message has no status field set to send or receive unexpectedly\n");
997 +              _dbus_verbose("deferred message has no status field set unexpectedly\n");
998                return BUS_RESULT_FALSE;
999              }
1000          }
1001 @@ -196,7 +274,8 @@ bus_dispatch_matches (BusTransaction *transaction,
1002          }
1003  
1004        /* Dispatch the message */
1005 -      if (!bus_transaction_send (transaction, addressed_recipient, message))
1006 +      if (!bus_transaction_send(transaction, addressed_recipient, message,
1007 +          dispatched_deferred_message != NULL ? TRUE : FALSE))
1008          {
1009            BUS_SET_OOM (error);
1010            return BUS_RESULT_FALSE;
1011 @@ -535,7 +614,7 @@ bus_dispatch (DBusConnection *connection,
1012     * match rules.
1013     */
1014    if (BUS_RESULT_LATER == bus_dispatch_matches (transaction, connection, addressed_recipient,
1015 -                                                message, &error))
1016 +                                                message, NULL, &error))
1017      {
1018        /* Roll back and dispatch the message once the policy result is available */
1019        bus_transaction_cancel_and_free (transaction);
1020 diff --git a/bus/dispatch.h b/bus/dispatch.h
1021 index afba6a2..f6102e8 100644
1022 --- a/bus/dispatch.h
1023 +++ b/bus/dispatch.h
1024 @@ -29,10 +29,11 @@
1025  
1026  dbus_bool_t bus_dispatch_add_connection    (DBusConnection *connection);
1027  void        bus_dispatch_remove_connection (DBusConnection *connection);
1028 -BusResult   bus_dispatch_matches           (BusTransaction *transaction,
1029 -                                            DBusConnection *sender,
1030 -                                            DBusConnection *recipient,
1031 -                                            DBusMessage    *message,
1032 -                                            DBusError      *error);
1033 +BusResult   bus_dispatch_matches           (BusTransaction     *transaction,
1034 +                                            DBusConnection     *sender,
1035 +                                            DBusConnection     *recipient,
1036 +                                            DBusMessage        *message,
1037 +                                            BusDeferredMessage *dispatched_deferred_message,
1038 +                                            DBusError           *error);
1039  
1040  #endif /* BUS_DISPATCH_H */
1041 diff --git a/bus/driver.c b/bus/driver.c
1042 index f414f64..d89a658 100644
1043 --- a/bus/driver.c
1044 +++ b/bus/driver.c
1045 @@ -254,7 +254,7 @@ bus_driver_send_service_owner_changed (const char     *service_name,
1046    if (!bus_transaction_capture (transaction, NULL, NULL, message))
1047      goto oom;
1048  
1049 -  res = bus_dispatch_matches (transaction, NULL, NULL, message, error);
1050 +  res = bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error);
1051    if (res == BUS_RESULT_TRUE)
1052      retval = TRUE;
1053    else
1054 diff --git a/bus/policy.c b/bus/policy.c
1055 index 7ee1ce5..b1fab0d 100644
1056 --- a/bus/policy.c
1057 +++ b/bus/policy.c
1058 @@ -1121,6 +1121,9 @@ bus_client_policy_check_can_send (DBusConnection      *sender,
1059  
1060        result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
1061            privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
1062 +      if (result == BUS_RESULT_LATER && deferred_message != NULL)
1063 +        bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
1064 +            *toggles, privilege);
1065      }
1066    else
1067      privilege = NULL;
1068 @@ -1370,6 +1373,9 @@ bus_client_policy_check_can_receive (BusClientPolicy     *policy,
1069  
1070        result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
1071                   privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, 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);
1075      }
1076    else
1077        privilege = NULL;