1c2ab2bcb209f0b811a618f5b9c503c2e40b763b
[AGL/meta-agl.git] / meta-security / recipes-core / dbus-cynara / dbus-cynara / 0003-Handle-unavailability-of-policy-results-for-broadcas.patch
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
5  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 Cherry picked from 1e231194610892dd4360224998d91336097b05a1 by Jose Bollo
23
24 Updated for dbus 1.10.20 by Scott Murray and José Bollo
25
26 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
27 Signed-off-by: Scott Murray <scott.murray@konsulko.com>
28
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,
35                                        entry->connection,
36                                        addressed_recipient,
37 -                                      entry->activation_message, &error);
38 +                                      entry->activation_message, NULL, &error);
39            if (res == BUS_RESULT_FALSE)
40              {
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);
48  
49                if (res == BUS_RESULT_TRUE)
50                  retval = TRUE;
51 diff --git a/bus/bus.c b/bus/bus.c
52 index 237efe3..5bb5637 100644
53 --- a/bus/bus.c
54 +++ b/bus/bus.c
55 @@ -1800,17 +1800,9 @@ bus_context_check_security_policy (BusContext     *context,
56      }
57  
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)))
62 -    {
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,
66 -          error);
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;
71 -    }
72  
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);
77      }
78  }
79 +
80 +void
81 +bus_context_complain_about_message (BusContext     *context,
82 +                                    const char     *error_name,
83 +                                    const char     *complaint,
84 +                                    int             matched_rules,
85 +                                    DBusMessage    *message,
86 +                                    DBusConnection *sender,
87 +                                    DBusConnection *proposed_recipient,
88 +                                    dbus_bool_t     requested_reply,
89 +                                    dbus_bool_t     log,
90 +                                    const char     *privilege,
91 +                                    DBusError      *error)
92 +{
93 +  complain_about_message(context, error_name, complaint, matched_rules, message, sender,
94 +      proposed_recipient, requested_reply, log, privilege, error);
95 +}
96 +
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,
102 +                                                        DBusError *error)
103 +{
104 +  if (recipient &&
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)))
107 +     {
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,
111 +           error);
112 +       _dbus_verbose ("security policy disallowing message due to full message queue\n");
113 +       return FALSE;
114 +     }
115 +  return TRUE;
116 +}
117 diff --git a/bus/bus.h b/bus/bus.h
118 index 82c32c8..1b08f7c 100644
119 --- a/bus/bus.h
120 +++ b/bus/bus.h
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);
124  
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,
130 +                                                                  DBusError *error);
131 +void              bus_context_complain_about_message             (BusContext     *context,
132 +                                                                  const char     *error_name,
133 +                                                                  const char     *complaint,
134 +                                                                  int             matched_rules,
135 +                                                                  DBusMessage    *message,
136 +                                                                  DBusConnection *sender,
137 +                                                                  DBusConnection *proposed_recipient,
138 +                                                                  dbus_bool_t     requested_reply,
139 +                                                                  dbus_bool_t     log,
140 +                                                                  const char     *privilege,
141 +                                                                  DBusError      *error);
142 +
143 +
144  #endif /* BUS_BUS_H */
145 diff --git a/bus/check.c b/bus/check.c
146 index 4b8a699..f3d283f 100644
147 --- a/bus/check.c
148 +++ b/bus/check.c
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;
154 +  int matched_rules;
155 +  const char *privilege;
156    dbus_bool_t full_dispatch;
157    BusDeferredMessageStatus status;
158    BusResult response;
159 @@ -135,6 +138,89 @@ bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
160    _dbus_connection_enable_dispatch(deferred_message->sender);
161  }
162  
163 +static void
164 +bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
165 +                                         BusResult result)
166 +{
167 +  int status;
168 +
169 +  _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
170 +
171 +  if (!bus_connection_is_active(deferred_message->proposed_recipient))
172 +    return;
173 +
174 +  status = deferred_message->status;
175 +
176 +  deferred_message->status = 0; /* mark message as not waiting for response */
177 +  deferred_message->response = result;
178 +
179 +  /*
180 +   * If send rule allows us to send message we still need to check receive rules.
181 +   */
182 +  if ((status & BUS_DEFERRED_MESSAGE_CHECK_SEND) && (result == BUS_RESULT_TRUE))
183 +    {
184 +      int toggles;
185 +      BusContext *context;
186 +      BusRegistry *registry;
187 +      BusClientPolicy *recipient_policy;
188 +      BusDeferredMessage *deferred_message_receive;
189 +
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);
193 +
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)
199 +        {
200 +          /* replace deferred message associated with send check with the one associated with
201 +           * receive check */
202 +          if (!bus_deferred_message_replace(deferred_message, deferred_message_receive))
203 +            {
204 +              /* failed to replace deferred message (due to oom). Set it to rejected */
205 +              deferred_message->response = BUS_RESULT_FALSE;
206 +            }
207 +        }
208 +    }
209 +
210 +  bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
211 +}
212 +
213 +static void
214 +queue_deferred_message_cancel_transaction_hook (void *data)
215 +{
216 +  BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
217 +  bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
218 +}
219 +
220 +
221 +dbus_bool_t
222 +bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
223 +                                         BusTransaction *transaction,
224 +                                         dbus_bool_t full_dispatch,
225 +                                         dbus_bool_t prepend)
226 +{
227 +  _dbus_assert(deferred_message != NULL);
228 +  _dbus_assert(deferred_message->proposed_recipient != NULL);
229 +
230 +  if (!bus_connection_queue_deferred_message(deferred_message->proposed_recipient,
231 +         deferred_message, prepend))
232 +    return FALSE;
233 +
234 +  if (!bus_transaction_add_cancel_hook(transaction, queue_deferred_message_cancel_transaction_hook,
235 +      deferred_message, NULL))
236 +    {
237 +      bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
238 +      return FALSE;
239 +    }
240 +  deferred_message->response_callback = bus_check_queued_message_reply_callback;
241 +  deferred_message->full_dispatch = full_dispatch;
242 +
243 +  return TRUE;
244 +}
245 +
246  static void
247  deferred_message_free_function(void *data)
248  {
249 @@ -159,6 +245,20 @@ bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
250    deferred_message->response_callback = bus_check_enable_dispatch_callback;
251  }
252  
253 +void
254 +bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
255 +                                            dbus_bool_t requested_reply,
256 +                                            int matched_rules,
257 +                                            const char *privilege)
258 +{
259 +  _dbus_assert(deferred_message != NULL);
260 +
261 +  deferred_message->requested_reply = requested_reply;
262 +  deferred_message->matched_rules = matched_rules;
263 +  deferred_message->privilege = privilege;
264 +}
265 +
266 +
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)
281       }
282  }
283  
284 +dbus_bool_t
285 +bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message, DBusError *error)
286 +{
287 +  BusContext *context = bus_connection_get_context(deferred_message->proposed_recipient);
288 +
289 +  return bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
290 +      deferred_message->sender, deferred_message->message, deferred_message->requested_reply,
291 +      error);
292 +}
293 +
294 +dbus_bool_t
295 +bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, BusTransaction *transaction, DBusError *error)
296 +{
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),
303 +                                       transaction,
304 +                                       deferred_message->sender, deferred_message->addressed_recipient,
305 +                                       deferred_message->message, error))
306 +    {
307 +      _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
308 +      return FALSE;
309 +    }
310 +  return TRUE;
311 +}
312 +
313 +void
314 +bus_deferred_message_create_error(BusDeferredMessage *deferred_message,
315 +    const char *error_message, DBusError *error)
316 +{
317 +  BusContext *context;
318 +  _dbus_assert (deferred_message->status == 0 && deferred_message->response == BUS_RESULT_FALSE);
319 +
320 +  if (deferred_message->sender == NULL)
321 +    return; /* error won't be sent to bus driver anyway */
322 +
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);
328 +}
329 +
330 +BusResult
331 +bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
332 +{
333 +  BusContext *context = bus_connection_get_context (deferred_message->proposed_recipient);
334 +  BusTransaction *transaction = bus_transaction_new (context);
335 +  BusResult result = BUS_RESULT_TRUE;
336 +  DBusError error;
337 +
338 +  if (transaction == NULL)
339 +    {
340 +      return BUS_RESULT_FALSE;
341 +    }
342 +
343 +  dbus_error_init(&error);
344 +
345 +  if (!deferred_message->full_dispatch)
346 +    {
347 +      result = deferred_message->response;
348 +      if (result == BUS_RESULT_TRUE)
349 +        {
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;
353 +        }
354 +      else if (result == BUS_RESULT_LATER)
355 +        {
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);
363 +
364 +          if (result == BUS_RESULT_LATER)
365 +            {
366 +              /* prepend at recipient */
367 +              if (!bus_deferred_message_queue_at_recipient(deferred_message2, transaction,
368 +                  FALSE, TRUE))
369 +                result = BUS_RESULT_FALSE;
370 +            }
371 +        }
372 +
373 +      /* silently drop messages on access denial */
374 +      if (result == BUS_RESULT_TRUE)
375 +        {
376 +          if (!bus_transaction_send (transaction, deferred_message->proposed_recipient, deferred_message->message, TRUE))
377 +            result = BUS_RESULT_FALSE;
378 +        }
379 +
380 +      bus_transaction_execute_and_free(transaction);
381 +
382 +      goto out;
383 +    }
384 +
385 +  /* do not attempt to send message if sender has disconnected */
386 +  if (deferred_message->sender != NULL && !bus_connection_is_active(deferred_message->sender))
387 +    {
388 +      bus_transaction_cancel_and_free(transaction);
389 +      result = BUS_RESULT_FALSE;
390 +      goto out;
391 +    }
392 +
393 +  result = bus_dispatch_matches(transaction, deferred_message->sender,
394 +      deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
395 +
396 +  if (result == BUS_RESULT_LATER)
397 +    {
398 +      /* Message deferring was already done in bus_dispatch_matches */
399 +      bus_transaction_cancel_and_free(transaction);
400 +      goto out;
401 +    }
402 +
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))
405 +    {
406 +      if (!dbus_connection_get_is_connected (deferred_message->sender))
407 +        {
408 +          /* If we disconnected it, we won't bother to send it any error
409 +           * messages.
410 +           */
411 +          _dbus_verbose ("Not sending error to connection we disconnected\n");
412 +        }
413 +      else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
414 +        {
415 +          bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
416 +
417 +          /* cancel transaction due to OOM */
418 +          if (transaction != NULL)
419 +            {
420 +              bus_transaction_cancel_and_free (transaction);
421 +              transaction = NULL;
422 +            }
423 +        }
424 +      else
425 +        {
426 +          /* Try to send the real error, if no mem to do that, send
427 +           * the OOM error
428 +           */
429 +          _dbus_assert (transaction != NULL);
430 +          if (!bus_transaction_send_error_reply (transaction, deferred_message->sender,
431 +                                                 &error, deferred_message->message))
432 +            {
433 +              bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
434 +
435 +              /* cancel transaction due to OOM */
436 +              if (transaction != NULL)
437 +                {
438 +                  bus_transaction_cancel_and_free (transaction);
439 +                  transaction = NULL;
440 +                }
441 +            }
442 +        }
443 +    }
444 +
445 +  if (transaction != NULL)
446 +    {
447 +      bus_transaction_execute_and_free (transaction);
448 +    }
449 +
450 +out:
451 +  dbus_error_free(&error);
452 +
453 +  return result;
454 +}
455 +
456 +dbus_bool_t
457 +bus_deferred_message_replace (BusDeferredMessage *old_message, BusDeferredMessage *new_message)
458 +{
459 +  if (bus_connection_replace_deferred_message(old_message->proposed_recipient,
460 +        old_message, new_message))
461 +    {
462 +      new_message->response_callback = old_message->response_callback;
463 +      new_message->full_dispatch = old_message->full_dispatch;
464 +      return TRUE;
465 +    }
466 +  return FALSE;
467 +}
468 +
469 +dbus_bool_t
470 +bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
471 +{
472 +  return deferred_message->status != 0;
473 +}
474 +
475 +DBusConnection *
476 +bus_deferred_message_get_recipient(BusDeferredMessage *deferred_message)
477 +{
478 +  return deferred_message->proposed_recipient;
479 +}
480 +
481  BusDeferredMessageStatus
482  bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
483  {
484    return deferred_message->status;
485  }
486  
487 +BusResult
488 +bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
489 +{
490 +  return deferred_message->response;
491 +}
492 +
493  void
494  bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
495                                          BusResult result)
496 @@ -310,3 +616,4 @@ bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
497        deferred_message->response_callback(deferred_message, result);
498      }
499  }
500 +
501 diff --git a/bus/check.h b/bus/check.h
502 index d177549..9c13c18 100644
503 --- a/bus/check.h
504 +++ b/bus/check.h
505 @@ -64,12 +64,37 @@ BusDeferredMessage *bus_deferred_message_new                (DBusMessage *messag
506  
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,
513                                                               BusResult result);
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);
522  
523  BusDeferredMessageStatus  bus_deferred_message_get_status   (BusDeferredMessage *deferred_message);
524  
525 +
526 +dbus_bool_t         bus_deferred_message_expect_method_reply (BusDeferredMessage *deferred_message,
527 +                                                              BusTransaction *transaction,
528 +                                                              DBusError *error);
529 +void                bus_deferred_message_create_error        (BusDeferredMessage *deferred_message,
530 +                                                              const char *error_message,
531 +                                                              DBusError *error);
532 +void                bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
533 +                                                                dbus_bool_t requested_reply,
534 +                                                                int matched_rules,
535 +                                                                const char *privilege);
536 +dbus_bool_t         bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message,
537 +                                                               DBusError *error);
538 +
539 +
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
547 @@ -31,11 +31,13 @@
548  #include "expirelist.h"
549  #include "selinux.h"
550  #include "apparmor.h"
551 +#include "check.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
559  #include <stdlib.h>
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 */
566  
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);
571      }
572  
573 +  bus_connection_clear_deferred_messages(connection);
574 +
575    bus_dispatch_remove_connection (connection);
576    
577    /* no more watching */
578 @@ -2307,7 +2312,7 @@ bus_transaction_capture (BusTransaction *transaction,
579      {
580        DBusConnection *recipient = link->data;
581  
582 -      if (!bus_transaction_send (transaction, recipient, message))
583 +      if (!bus_transaction_send (transaction, recipient, message, FALSE))
584          goto out;
585      }
586  
587 @@ -2361,6 +2366,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
588  {
589    DBusError error = DBUS_ERROR_INIT;
590    BusResult res;
591 +  BusDeferredMessage *deferred_message;
592  
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),
597                                             transaction,
598                                             NULL, connection, connection, message, NULL,
599 -                                           &error, NULL);
600 +                                           &error, &deferred_message);
601    if (res == BUS_RESULT_FALSE)
602      {
603        if (!bus_transaction_capture_error_reply (transaction, connection,
604 @@ -2419,18 +2425,20 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
605      }
606    else if (res == BUS_RESULT_LATER)
607      {
608 -      _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
609        dbus_error_free (&error);
610 -      return TRUE;
611 +      if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
612 +        return FALSE;
613 +      return TRUE; /* pretend to have sent it */
614      }
615  
616 -  return bus_transaction_send (transaction, connection, message);
617 +  return bus_transaction_send (transaction, connection, message, FALSE);
618  }
619  
620  dbus_bool_t
621  bus_transaction_send (BusTransaction *transaction,
622                        DBusConnection *connection,
623 -                      DBusMessage    *message)
624 +                      DBusMessage    *message,
625 +                      dbus_bool_t     deferred_dispatch)
626  {
627    MessageToSend *to_send;
628    BusConnectionData *d;
629 @@ -2456,7 +2464,28 @@ bus_transaction_send (BusTransaction *transaction,
630    
631    d = BUS_CONNECTION_DATA (connection);
632    _dbus_assert (d != NULL);
633 -  
634 +
635 +  if (!deferred_dispatch && d->deferred_messages != NULL)
636 +    {
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,
642 +                                                   NULL,
643 +                                                   NULL,
644 +                                                   connection,
645 +                                                   BUS_RESULT_TRUE);
646 +      if (deferred_message == NULL)
647 +        return FALSE;
648 +
649 +      success = bus_deferred_message_queue_at_recipient(deferred_message, transaction,
650 +          FALSE, FALSE);
651 +      bus_deferred_message_unref(deferred_message);
652 +
653 +      return success;
654 +    }
655 +
656    to_send = dbus_new (MessageToSend, 1);
657    if (to_send == NULL)
658      {
659 @@ -2708,6 +2737,131 @@ bus_transaction_add_cancel_hook (BusTransaction               *transaction,
660    return TRUE;
661  }
662  
663 +void
664 +bus_connection_dispatch_deferred (DBusConnection *connection)
665 +{
666 +  BusDeferredMessage *message;
667 +
668 +  _dbus_return_if_fail (connection != NULL);
669 +
670 +  while ((message = bus_connection_pop_deferred_message(connection)) != NULL)
671 +    {
672 +      bus_deferred_message_dispatch(message);
673 +      bus_deferred_message_unref(message);
674 +    }
675 +}
676 +
677 +dbus_bool_t
678 +bus_connection_has_deferred_messages (DBusConnection *connection)
679 +{
680 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
681 +  return d->deferred_messages != NULL ? TRUE : FALSE;
682 +}
683 +
684 +dbus_bool_t
685 +bus_connection_queue_deferred_message (DBusConnection *connection,
686 +                                       BusDeferredMessage *message,
687 +                                       dbus_bool_t prepend)
688 +{
689 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
690 +  dbus_bool_t success;
691 +  if (prepend)
692 +    success = _dbus_list_prepend(&d->deferred_messages, message);
693 +  else
694 +    success = _dbus_list_append(&d->deferred_messages, message);
695 +
696 +  if (success)
697 +    {
698 +      bus_deferred_message_ref(message);
699 +      return TRUE;
700 +    }
701 +
702 +  return FALSE;
703 +}
704 +
705 +dbus_bool_t
706 +bus_connection_replace_deferred_message (DBusConnection *connection,
707 +                                         BusDeferredMessage *oldMessage,
708 +                                         BusDeferredMessage *newMessage)
709 +{
710 +  DBusList *link;
711 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
712 +
713 +  link = _dbus_list_find_first(&d->deferred_messages, oldMessage);
714 +  if (link == NULL)
715 +    return FALSE;
716 +
717 +  if (!_dbus_list_insert_after(&d->deferred_messages, link, newMessage))
718 +    return FALSE;
719 +
720 +  bus_deferred_message_ref(newMessage);
721 +  _dbus_list_remove_link(&d->deferred_messages, link);
722 +  bus_deferred_message_unref(oldMessage);
723 +  return TRUE;
724 +}
725 +
726 +BusDeferredMessage *
727 +bus_connection_pop_deferred_message (DBusConnection *connection)
728 +{
729 +  DBusList *link;
730 +  BusDeferredMessage *message;
731 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
732 +
733 +  link =_dbus_list_get_first_link(&d->deferred_messages);
734 +  if (link != NULL)
735 +    {
736 +      message = link->data;
737 +      if (!bus_deferred_message_waits_for_check(message))
738 +        {
739 +          _dbus_list_remove_link(&d->deferred_messages, link);
740 +          return message;
741 +        }
742 +    }
743 +
744 +  return NULL;
745 +}
746 +
747 +dbus_bool_t
748 +bus_connection_putback_deferred_message (DBusConnection *connection, BusDeferredMessage *message)
749 +{
750 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
751 +  if (_dbus_list_prepend(&d->deferred_messages, message))
752 +    {
753 +      return TRUE;
754 +    }
755 +  return FALSE;
756 +}
757 +
758 +void
759 +bus_connection_clear_deferred_messages (DBusConnection *connection)
760 +{
761 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
762 +  DBusList *link;
763 +  DBusList *next;
764 +  BusDeferredMessage *message;
765 +
766 +  link =_dbus_list_get_first_link(&d->deferred_messages);
767 +  while (link != NULL)
768 +    {
769 +      next = _dbus_list_get_next_link (&d->deferred_messages, link);
770 +      message = link->data;
771 +
772 +      bus_deferred_message_unref(message);
773 +      _dbus_list_remove_link(&d->deferred_messages, link);
774 +
775 +      link = next;
776 +    }
777 +}
778 +
779 +void
780 +bus_connection_remove_deferred_message (DBusConnection *connection,
781 +                                        BusDeferredMessage *message)
782 +{
783 +  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
784 +  if (_dbus_list_remove(&d->deferred_messages, message))
785 +    bus_deferred_message_unref(message);
786 +}
787 +
788  int
789  bus_connections_get_n_active (BusConnections *connections)
790  {
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);
798  
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);
813 +
814 +
815  /* called by signals.c */
816  dbus_bool_t bus_connection_add_match_rule      (DBusConnection *connection,
817                                                  BusMatchRule   *rule);
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
830 --- a/bus/dispatch.c
831 +++ b/bus/dispatch.c
832 @@ -33,6 +33,7 @@
833  #include "utils.h"
834  #include "bus.h"
835  #include "signals.h"
836 +#include "dispatch.h"
837  #include "test.h"
838  #include <dbus/dbus-internals.h>
839  #include <dbus/dbus-connection-internal.h>
840 @@ -77,7 +78,7 @@ send_one_message (DBusConnection *connection,
841                                            NULL,
842                                            &stack_error,
843                                            &deferred_message);
844 -  if (result != BUS_RESULT_TRUE)
845 +  if (result == BUS_RESULT_FALSE)
846      {
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 */
851      }
852  
853 +  if (result == BUS_RESULT_LATER)
854 +    {
855 +      if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
856 +        {
857 +          BUS_SET_OOM (error);
858 +          return FALSE;
859 +        }
860 +      return TRUE; /* pretend to have sent it */
861 +    }
862 +
863    if (!bus_transaction_send (transaction,
864                               connection,
865 -                             message))
866 +                             message, FALSE))
867      {
868        BUS_SET_OOM (error);
869        return FALSE;
870 @@ -124,11 +135,12 @@ send_one_message (DBusConnection *connection,
871  }
872  
873  BusResult
874 -bus_dispatch_matches (BusTransaction *transaction,
875 -                      DBusConnection *sender,
876 -                      DBusConnection *addressed_recipient,
877 -                      DBusMessage    *message,
878 -                      DBusError      *error)
879 +bus_dispatch_matches (BusTransaction     *transaction,
880 +                      DBusConnection     *sender,
881 +                      DBusConnection     *addressed_recipient,
882 +                      DBusMessage        *message,
883 +                      BusDeferredMessage *dispatched_deferred_message,
884 +                      DBusError          *error)
885  {
886    DBusError tmp_error;
887    BusConnections *connections;
888 @@ -137,7 +149,6 @@ bus_dispatch_matches (BusTransaction *transaction,
889    DBusList *link;
890    BusContext *context;
891    BusDeferredMessage *deferred_message;
892 -  BusResult res;
893  
894    _DBUS_ASSERT_ERROR_IS_CLEAR (error);
895  
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)
899      {
900 -      res = bus_context_check_security_policy (context, transaction,
901 +      BusResult result;
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
904 +       */
905 +      if (dispatched_deferred_message == NULL && bus_connection_has_deferred_messages(addressed_recipient))
906 +        {
907 +          deferred_message = bus_deferred_message_new(message, sender,
908 +              addressed_recipient, addressed_recipient, BUS_RESULT_LATER);
909 +
910 +          if (deferred_message == NULL)
911 +            {
912 +              BUS_SET_OOM(error);
913 +              return BUS_RESULT_FALSE;
914 +            }
915 +
916 +          if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
917 +            {
918 +              bus_deferred_message_unref(deferred_message);
919 +              BUS_SET_OOM(error);
920 +              return BUS_RESULT_FALSE;
921 +            }
922 +
923 +          bus_deferred_message_unref(deferred_message);
924 +          return BUS_RESULT_TRUE; /* pretend to have sent it */
925 +        }
926 +
927 +      if (dispatched_deferred_message != NULL)
928 +        {
929 +          result = bus_deferred_message_get_response(dispatched_deferred_message);
930 +          if (result == BUS_RESULT_TRUE)
931 +            {
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
935 +               */
936 +              if (!bus_deferred_message_check_message_limits(dispatched_deferred_message, error))
937 +                return BUS_RESULT_FALSE;
938 +
939 +              if (!bus_deferred_message_expect_method_reply(dispatched_deferred_message, transaction, error))
940 +                return BUS_RESULT_FALSE;
941 +            }
942 +          else if (result == BUS_RESULT_FALSE)
943 +            {
944 +              bus_deferred_message_create_error(dispatched_deferred_message, "Rejected message", error);
945 +              return BUS_RESULT_FALSE;
946 +            }
947 +        }
948 +      else
949 +        result = BUS_RESULT_LATER;
950 +
951 +      if (result == BUS_RESULT_LATER)
952 +        result = bus_context_check_security_policy (context, transaction,
953                                                 sender, addressed_recipient,
954                                                 addressed_recipient,
955                                                 message, NULL, error,
956                                                 &deferred_message);
957 -      if (res == BUS_RESULT_FALSE)
958 +
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)
963          {
964            BusDeferredMessageStatus status;
965 +
966 +          if (dispatched_deferred_message != NULL)
967 +            {
968 +              /* for deferred dispatch prepend message at the recipient */
969 +              if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, TRUE))
970 +                {
971 +                  BUS_SET_OOM(error);
972 +                  return BUS_RESULT_FALSE;
973 +                }
974 +              return BUS_RESULT_TRUE; /* pretend to have sent it */
975 +            }
976 +
977            status = bus_deferred_message_get_status(deferred_message);
978  
979            if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
980 @@ -173,13 +248,18 @@ bus_dispatch_matches (BusTransaction *transaction,
981              }
982            else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
983              {
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))
989 +                {
990 +                  BUS_SET_OOM(error);
991 +                  return BUS_RESULT_FALSE;
992 +                }
993 +
994 +              return BUS_RESULT_TRUE; /* pretend to have sent it */
995              }
996            else
997              {
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;
1001              }
1002          }
1003 @@ -196,7 +276,8 @@ bus_dispatch_matches (BusTransaction *transaction,
1004          }
1005  
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))
1010          {
1011            BUS_SET_OOM (error);
1012            return BUS_RESULT_FALSE;
1013 @@ -534,7 +615,7 @@ bus_dispatch (DBusConnection *connection,
1014     * match rules.
1015     */
1016    if (BUS_RESULT_LATER == bus_dispatch_matches (transaction, connection, addressed_recipient,
1017 -                                                message, &error))
1018 +                                                message, NULL, &error))
1019      {
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
1026 @@ -29,10 +29,11 @@
1027  
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);
1041  
1042  #endif /* BUS_DISPATCH_H */
1043 diff --git a/bus/driver.c b/bus/driver.c
1044 index f414f64..d89a658 100644
1045 --- a/bus/driver.c
1046 +++ b/bus/driver.c
1047 @@ -254,7 +254,7 @@ bus_driver_send_service_owner_changed (const char     *service_name,
1048    if (!bus_transaction_capture (transaction, NULL, NULL, message))
1049      goto oom;
1050  
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)
1054      retval = TRUE;
1055    else
1056 diff --git a/bus/policy.c b/bus/policy.c
1057 index 7ee1ce5..b1fab0d 100644
1058 --- a/bus/policy.c
1059 +++ b/bus/policy.c
1060 @@ -1121,6 +1121,9 @@ bus_client_policy_check_can_send (DBusConnection      *sender,
1061  
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);
1067      }
1068    else
1069      privilege = NULL;
1070 @@ -1370,6 +1373,9 @@ bus_client_policy_check_can_receive (BusClientPolicy     *policy,
1071  
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);
1077      }
1078    else
1079        privilege = NULL;
1080 -- 
1081 2.17.2
1082