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