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