Prepare master for new framework integration
[AGL/meta-agl.git] / meta-app-framework / recipes-core / dbus-cynagora / dbus-cynagora / 0002-Disable-message-dispatching-when-send-rule-result-is.patch
diff --git a/meta-app-framework/recipes-core/dbus-cynagora/dbus-cynagora/0002-Disable-message-dispatching-when-send-rule-result-is.patch b/meta-app-framework/recipes-core/dbus-cynagora/dbus-cynagora/0002-Disable-message-dispatching-when-send-rule-result-is.patch
deleted file mode 100644 (file)
index bac8cf9..0000000
+++ /dev/null
@@ -1,967 +0,0 @@
-From c2f4ba585c777b731df6b6b8a165b6cc4dc5d639 Mon Sep 17 00:00:00 2001
-From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
-Date: Fri, 28 Nov 2014 12:07:39 +0100
-Subject: [PATCH 2/8] Disable message dispatching when send rule result is not
- known
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When unicast message is sent to addressed recipient and policy result
-is not available message dispatch from the sender is disabled.
-This also means that any further messages from the given connection are
-put into the incoming queue without being processed. If response is received
-message dispatching is resumed. This time answer is attached to the message
-which is now processed synchronously.
-Receive rule result unavailability is not yet handled - such messages are
-rejected. Also, if message is sent to non-addressed recipient and policy result
-is unknown, message is silently dropped.
-
-Cherry-picked from b1b87ad9f20b2052c28431b48e81073078a745ce
-by Jose Bollo.
-
-Updated for dbus 1.10.20 by Scott Murray and José Bollo
-
-Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-Signed-off-by: Scott Murray <scott.murray@konsulko.com>
----
- bus/activation.c                |  76 +++++++++++--
- bus/check.c                     | 109 +++++++++++++++++--
- bus/check.h                     |  10 ++
- bus/cynara.c                    |   1 -
- bus/dispatch.c                  | 184 ++++++++++++++++++++++++++++----
- bus/dispatch.h                  |   2 +-
- bus/driver.c                    |  12 ++-
- dbus/dbus-connection-internal.h |  15 +++
- dbus/dbus-connection.c          | 125 +++++++++++++++++++++-
- dbus/dbus-list.c                |  29 +++++
- dbus/dbus-list.h                |   3 +
- dbus/dbus-shared.h              |   3 +-
- 12 files changed, 528 insertions(+), 41 deletions(-)
-
-diff --git a/bus/activation.c b/bus/activation.c
-index f9c6c62..8301b59 100644
---- a/bus/activation.c
-+++ b/bus/activation.c
-@@ -32,6 +32,7 @@
- #include "services.h"
- #include "test.h"
- #include "utils.h"
-+#include <dbus/dbus-connection-internal.h>
- #include <dbus/dbus-internals.h>
- #include <dbus/dbus-hash.h>
- #include <dbus/dbus-list.h>
-@@ -94,6 +95,8 @@ struct BusPendingActivationEntry
-   DBusConnection *connection;
-   dbus_bool_t auto_activation;
-+
-+  dbus_bool_t is_put_back;
- };
- typedef struct
-@@ -1241,20 +1244,23 @@ bus_activation_send_pending_auto_activation_messages (BusActivation  *activation
-       BusPendingActivationEntry *entry = link->data;
-       DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
--      if (entry->auto_activation && (entry->connection == NULL || dbus_connection_get_is_connected (entry->connection)))
-+      if (entry->auto_activation && !entry->is_put_back &&
-+          (entry->connection == NULL || dbus_connection_get_is_connected (entry->connection)))
-         {
-           DBusConnection *addressed_recipient;
-           DBusError error;
-+          BusResult res;
-           dbus_error_init (&error);
-           addressed_recipient = bus_service_get_primary_owners_connection (service);
-           /* Resume dispatching where we left off in bus_dispatch() */
--          if (!bus_dispatch_matches (transaction,
--                                     entry->connection,
--                                     addressed_recipient,
--                                     entry->activation_message, &error))
-+          res = bus_dispatch_matches (transaction,
-+                                      entry->connection,
-+                                      addressed_recipient,
-+                                      entry->activation_message, &error);
-+          if (res == BUS_RESULT_FALSE)
-             {
-               /* If permission is denied, we just want to return the error
-                * to the original method invoker; in particular, we don't
-@@ -1266,11 +1272,44 @@ bus_activation_send_pending_auto_activation_messages (BusActivation  *activation
-                   bus_connection_send_oom_error (entry->connection,
-                                                  entry->activation_message);
-                 }
--
-               dbus_error_free (&error);
-               link = next;
-               continue;
-             }
-+          else if (res == BUS_RESULT_LATER)
-+            {
-+              DBusList *putback_message_link = link;
-+              DBusMessage *last_inserted_message = NULL;
-+
-+              /* NULL entry->connection implies sending pending ActivationRequest message to systemd */
-+              if (entry->connection == NULL)
-+                {
-+                  _dbus_assert_not_reached ("bus_dispatch_matches returned BUS_RESULT_LATER unexpectedly when sender is NULL");
-+                  link = next;
-+                  continue;
-+                }
-+
-+              /**
-+               * Getting here means that policy check result is not yet available and dispatching
-+               * messages from entry->connection has been disabled.
-+               * Let's put back all messages for the given connection in the incoming queue and mark
-+               * this entry as put back so they are not handled twice.
-+               */
-+              while (putback_message_link != NULL)
-+                {
-+                  BusPendingActivationEntry *putback_message = putback_message_link->data;
-+                  if (putback_message->connection == entry->connection)
-+                    {
-+                      if (!_dbus_connection_putback_message (putback_message->connection, last_inserted_message,
-+                            putback_message->activation_message, &error))
-+                        goto error;
-+                      last_inserted_message = putback_message->activation_message;
-+                      putback_message->is_put_back = TRUE;
-+                    }
-+
-+                  putback_message_link = _dbus_list_get_next_link(&pending_activation->entries, putback_message_link);
-+                }
-+            }
-         }
-       link = next;
-@@ -1287,6 +1326,19 @@ bus_activation_send_pending_auto_activation_messages (BusActivation  *activation
-   return TRUE;
-  error:
-+  /* remove all messages that have been put to connections' incoming queues */
-+  link = _dbus_list_get_first_link (&pending_activation->entries);
-+  while (link != NULL)
-+    {
-+      BusPendingActivationEntry *entry = link->data;
-+      if (entry->is_put_back)
-+        {
-+          _dbus_connection_remove_message(entry->connection, entry->activation_message);
-+          entry->is_put_back = FALSE;
-+        }
-+      link = _dbus_list_get_next_link(&pending_activation->entries, link);
-+    }
-+
-   return FALSE;
- }
-@@ -2079,6 +2131,7 @@ bus_activation_activate_service (BusActivation  *activation,
-           if (service != NULL)
-             {
-+              BusResult res;
-               bus_context_log (activation->context,
-                                DBUS_SYSTEM_LOG_INFO, "Activating via systemd: service name='%s' unit='%s' requested by '%s' (%s)",
-                                service_name,
-@@ -2086,8 +2139,17 @@ bus_activation_activate_service (BusActivation  *activation,
-                                bus_connection_get_name (connection),
-                                bus_connection_get_loginfo (connection));
-               /* Wonderful, systemd is connected, let's just send the msg */
--              retval = bus_dispatch_matches (activation_transaction, NULL,
-+              res = bus_dispatch_matches (activation_transaction, NULL,
-                                              systemd, message, error);
-+
-+              if (res == BUS_RESULT_TRUE)
-+                retval = TRUE;
-+              else
-+                {
-+                  retval = FALSE;
-+                  if (res == BUS_RESULT_LATER)
-+                    _dbus_verbose("Unexpectedly need time to check message from bus driver to systemd - dropping the message.\n");
-+                }
-             }
-           else
-             {
-diff --git a/bus/check.c b/bus/check.c
-index 5b72d31..4b8a699 100644
---- a/bus/check.c
-+++ b/bus/check.c
-@@ -55,6 +55,8 @@ typedef struct BusDeferredMessage
-   BusCheckResponseFunc response_callback;
- } BusDeferredMessage;
-+static dbus_int32_t deferred_message_data_slot = -1;
-+
- BusCheck *
- bus_check_new (BusContext *context, DBusError *error)
- {
-@@ -67,11 +69,19 @@ bus_check_new (BusContext *context, DBusError *error)
-       return NULL;
-     }
-+  if (!dbus_message_allocate_data_slot(&deferred_message_data_slot))
-+    {
-+      dbus_free(check);
-+      BUS_SET_OOM(error);
-+      return NULL;
-+    }
-+
-   check->refcount = 1;
-   check->context = context;
-   check->cynara = bus_cynara_new(check, error);
-   if (dbus_error_is_set(error))
-     {
-+      dbus_message_free_data_slot(&deferred_message_data_slot);
-       dbus_free(check);
-       return NULL;
-     }
-@@ -98,6 +108,7 @@ bus_check_unref (BusCheck *check)
-   if (check->refcount == 0)
-     {
-       bus_cynara_unref(check->cynara);
-+      dbus_message_free_data_slot(&deferred_message_data_slot);
-       dbus_free(check);
-     }
- }
-@@ -114,6 +125,45 @@ bus_check_get_cynara (BusCheck *check)
-   return check->cynara;
- }
-+static void
-+bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
-+                                    BusResult result)
-+{
-+  _dbus_verbose("bus_check_enable_dispatch_callback called deferred_message=%p\n", deferred_message);
-+
-+  deferred_message->response = result;
-+  _dbus_connection_enable_dispatch(deferred_message->sender);
-+}
-+
-+static void
-+deferred_message_free_function(void *data)
-+{
-+  BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
-+  bus_deferred_message_unref(deferred_message);
-+}
-+
-+void
-+bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
-+{
-+  _dbus_assert(deferred_message != NULL);
-+  _dbus_assert(deferred_message->sender != NULL);
-+
-+  if (dbus_message_get_data(deferred_message->message, deferred_message_data_slot) == NULL)
-+    {
-+      if (dbus_message_set_data(deferred_message->message, deferred_message_data_slot, deferred_message,
-+          deferred_message_free_function))
-+        bus_deferred_message_ref(deferred_message);
-+    }
-+
-+  _dbus_connection_disable_dispatch(deferred_message->sender);
-+  deferred_message->response_callback = bus_check_enable_dispatch_callback;
-+}
-+
-+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
-+BusResult (*bus_check_test_override) (DBusConnection *connection,
-+                                        const char *privilege);
-+#endif
-+
- BusResult
- bus_check_privilege (BusCheck *check,
-                      DBusMessage *message,
-@@ -124,6 +174,7 @@ bus_check_privilege (BusCheck *check,
-                      BusDeferredMessageStatus check_type,
-                      BusDeferredMessage **deferred_message)
- {
-+  BusDeferredMessage *previous_deferred_message;
-   BusResult result = BUS_RESULT_FALSE;
- #ifdef DBUS_ENABLE_CYNARA
-   BusCynara *cynara;
-@@ -137,16 +188,54 @@ bus_check_privilege (BusCheck *check,
-       return BUS_RESULT_FALSE;
-     }
--  /* ask policy checkers */
--#ifdef DBUS_ENABLE_CYNARA
--  cynara = bus_check_get_cynara(check);
--  result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
--      proposed_recipient, privilege, check_type, deferred_message);
-+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
-+  if (bus_check_test_override)
-+    return bus_check_test_override (connection, privilege);
- #endif
--  if (result == BUS_RESULT_LATER && deferred_message != NULL)
-+  previous_deferred_message = dbus_message_get_data(message, deferred_message_data_slot);
-+  /* check if message blocked at sender's queue is being processed */
-+  if (previous_deferred_message != NULL)
-+    {
-+      if ((check_type & BUS_DEFERRED_MESSAGE_CHECK_SEND) &&
-+          !(previous_deferred_message->status & BUS_DEFERRED_MESSAGE_CHECK_SEND))
-+        {
-+          /**
-+           * Message has been deferred due to receive or own rule which means that sending this message
-+           * is allowed - it must have been checked previously.
-+           * This might happen when client calls RequestName method which depending on security
-+           * policy might result in both "can_send" and "can_own" Cynara checks.
-+           */
-+          result = BUS_RESULT_TRUE;
-+        }
-+      else
-+        {
-+          result = previous_deferred_message->response;
-+          if (result == BUS_RESULT_LATER)
-+            {
-+              /* result is still not known - reuse deferred message object */
-+              if (deferred_message != NULL)
-+                *deferred_message = previous_deferred_message;
-+            }
-+          else
-+            {
-+              /* result is available - we can remove deferred message from the processed message */
-+              dbus_message_set_data(message, deferred_message_data_slot, NULL, NULL);
-+            }
-+        }
-+    }
-+  else
-     {
--      (*deferred_message)->status |= check_type;
-+      /* ask policy checkers */
-+#ifdef DBUS_ENABLE_CYNARA
-+      cynara = bus_check_get_cynara(check);
-+      result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
-+          proposed_recipient, privilege, check_type, deferred_message);
-+#endif
-+      if (result == BUS_RESULT_LATER && deferred_message != NULL)
-+        {
-+          (*deferred_message)->status |= check_type;
-+        }
-     }
-   return result;
- }
-@@ -206,6 +295,12 @@ bus_deferred_message_unref (BusDeferredMessage *deferred_message)
-      }
- }
-+BusDeferredMessageStatus
-+bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
-+{
-+  return deferred_message->status;
-+}
-+
- void
- bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
-                                         BusResult result)
-diff --git a/bus/check.h b/bus/check.h
-index c3fcaf9..d177549 100644
---- a/bus/check.h
-+++ b/bus/check.h
-@@ -55,6 +55,7 @@ BusResult   bus_check_privilege   (BusCheck *check,
-                                    BusDeferredMessageStatus check_type,
-                                    BusDeferredMessage **deferred_message);
-+
- BusDeferredMessage *bus_deferred_message_new                (DBusMessage *message,
-                                                              DBusConnection *sender,
-                                                              DBusConnection *addressed_recipient,
-@@ -65,4 +66,13 @@ BusDeferredMessage *bus_deferred_message_ref                (BusDeferredMessage
- void                bus_deferred_message_unref              (BusDeferredMessage *deferred_message);
- void                bus_deferred_message_response_received  (BusDeferredMessage *deferred_message,
-                                                              BusResult result);
-+void                bus_deferred_message_disable_sender     (BusDeferredMessage *deferred_message);
-+
-+BusDeferredMessageStatus  bus_deferred_message_get_status   (BusDeferredMessage *deferred_message);
-+
-+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
-+extern BusResult (*bus_check_test_override) (DBusConnection *connection,
-+                                               const char *privilege);
-+#endif
-+
- #endif /* BUS_CHECK_H */
-diff --git a/bus/cynara.c b/bus/cynara.c
-index 57a4c45..77aed62 100644
---- a/bus/cynara.c
-+++ b/bus/cynara.c
-@@ -36,7 +36,6 @@
- #include <cynara-client-async.h>
- #endif
--
- #ifdef DBUS_ENABLE_CYNARA
- typedef struct BusCynara
- {
-diff --git a/bus/dispatch.c b/bus/dispatch.c
-index d3867f7..50a22a3 100644
---- a/bus/dispatch.c
-+++ b/bus/dispatch.c
-@@ -35,6 +35,7 @@
- #include "signals.h"
- #include "test.h"
- #include <dbus/dbus-internals.h>
-+#include <dbus/dbus-connection-internal.h>
- #include <dbus/dbus-misc.h>
- #include <string.h>
-@@ -122,7 +123,7 @@ send_one_message (DBusConnection *connection,
-   return TRUE;
- }
--dbus_bool_t
-+BusResult
- bus_dispatch_matches (BusTransaction *transaction,
-                       DBusConnection *sender,
-                       DBusConnection *addressed_recipient,
-@@ -158,13 +159,29 @@ bus_dispatch_matches (BusTransaction *transaction,
-                                                message, NULL, error,
-                                                &deferred_message);
-       if (res == BUS_RESULT_FALSE)
--        return FALSE;
-+        return BUS_RESULT_FALSE;
-       else if (res == BUS_RESULT_LATER)
-         {
--          dbus_set_error (error,
--                          DBUS_ERROR_ACCESS_DENIED,
--                          "Rejecting message because time is needed to check security policy");
--          return FALSE;
-+          BusDeferredMessageStatus status;
-+          status = bus_deferred_message_get_status(deferred_message);
-+
-+          if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
-+            {
-+              /* send rule result not available - disable dispatching messages from the sender */
-+              bus_deferred_message_disable_sender(deferred_message);
-+              return BUS_RESULT_LATER;
-+            }
-+          else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
-+            {
-+              dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
-+                              "Rejecting message because time is needed to check security policy");
-+              return BUS_RESULT_FALSE;
-+            }
-+          else
-+            {
-+              _dbus_verbose("deferred message has no status field set to send or receive unexpectedly\n");
-+              return BUS_RESULT_FALSE;
-+            }
-         }
-       if (dbus_message_contains_unix_fds (message) &&
-@@ -175,14 +192,14 @@ bus_dispatch_matches (BusTransaction *transaction,
-                           DBUS_ERROR_NOT_SUPPORTED,
-                           "Tried to send message with Unix file descriptors"
-                           "to a client that doesn't support that.");
--          return FALSE;
--      }
-+          return BUS_RESULT_FALSE;
-+        }
-       /* Dispatch the message */
-       if (!bus_transaction_send (transaction, addressed_recipient, message))
-         {
-           BUS_SET_OOM (error);
--          return FALSE;
-+          return BUS_RESULT_FALSE;
-         }
-     }
-@@ -197,7 +214,7 @@ bus_dispatch_matches (BusTransaction *transaction,
-                                       &recipients))
-     {
-       BUS_SET_OOM (error);
--      return FALSE;
-+      return BUS_RESULT_FALSE;
-     }
-   link = _dbus_list_get_first_link (&recipients);
-@@ -219,10 +236,10 @@ bus_dispatch_matches (BusTransaction *transaction,
-   if (dbus_error_is_set (&tmp_error))
-     {
-       dbus_move_error (&tmp_error, error);
--      return FALSE;
-+      return BUS_RESULT_FALSE;
-     }
-   else
--    return TRUE;
-+    return BUS_RESULT_TRUE;
- }
- static DBusHandlerResult
-@@ -409,10 +426,12 @@ bus_dispatch (DBusConnection *connection,
-         }
-       else if (res == BUS_RESULT_LATER)
-         {
--          dbus_set_error (&error,
--                          DBUS_ERROR_ACCESS_DENIED,
--                          "Rejecting message because time is needed to check security policy");
--          _dbus_verbose ("Security policy needs time to check policy. Dropping message\n");
-+          /* Disable dispatching messages from the sender,
-+           * roll back and dispatch the message once the policy result is available */
-+          bus_deferred_message_disable_sender(deferred_message);
-+          bus_transaction_cancel_and_free (transaction);
-+          transaction = NULL;
-+          result = DBUS_HANDLER_RESULT_LATER;
-           goto out;
-         }
-@@ -514,8 +533,14 @@ bus_dispatch (DBusConnection *connection,
-    * addressed_recipient == NULL), and match it against other connections'
-    * match rules.
-    */
--  if (!bus_dispatch_matches (transaction, connection, addressed_recipient, message, &error))
--    goto out;
-+  if (BUS_RESULT_LATER == bus_dispatch_matches (transaction, connection, addressed_recipient,
-+                                                message, &error))
-+    {
-+      /* Roll back and dispatch the message once the policy result is available */
-+      bus_transaction_cancel_and_free (transaction);
-+      transaction = NULL;
-+      result = DBUS_HANDLER_RESULT_LATER;
-+    }
-  out:
-   if (dbus_error_is_set (&error))
-@@ -5060,9 +5085,132 @@ bus_dispatch_test_conf_fail (const DBusString *test_data_dir,
- }
- #endif
-+typedef struct {
-+  DBusTimeout *timeout;
-+  DBusConnection *connection;
-+  dbus_bool_t timedout;
-+  int check_counter;
-+} BusTestCheckData;
-+
-+static BusTestCheckData *cdata;
-+
-+static dbus_bool_t
-+bus_dispatch_test_check_timeout (void *data)
-+{
-+  _dbus_verbose ("timeout triggered - pretend that privilege check result is available\n");
-+
-+  /* should only happen once during the test */
-+  _dbus_assert (!cdata->timedout);
-+  cdata->timedout = TRUE;
-+  _dbus_connection_enable_dispatch (cdata->connection);
-+
-+  /* don't call this again */
-+  _dbus_loop_remove_timeout (bus_connection_get_loop (cdata->connection),
-+                             cdata->timeout);
-+  dbus_connection_unref (cdata->connection);
-+  cdata->connection = NULL;
-+  return TRUE;
-+}
-+
-+static BusResult
-+bus_dispatch_test_check_override (DBusConnection *connection,
-+                                  const char *privilege)
-+{
-+  _dbus_verbose ("overriding privilege check %s #%d\n", privilege, cdata->check_counter);
-+  cdata->check_counter++;
-+  if (!cdata->timedout)
-+    {
-+      dbus_bool_t added;
-+
-+      /* Should be the first privilege check for the "Echo" method. */
-+      _dbus_assert (cdata->check_counter == 1);
-+      cdata->timeout = _dbus_timeout_new (1, bus_dispatch_test_check_timeout,
-+                                          NULL, NULL);
-+      _dbus_assert (cdata->timeout);
-+      added = _dbus_loop_add_timeout (bus_connection_get_loop (connection),
-+                                      cdata->timeout);
-+      _dbus_assert (added);
-+      cdata->connection = connection;
-+      dbus_connection_ref (connection);
-+      _dbus_connection_disable_dispatch (connection);
-+      return BUS_RESULT_LATER;
-+    }
-+  else
-+    {
-+      /* Should only be checked one more time, and this time succeeds. */
-+      _dbus_assert (cdata->check_counter == 2);
-+      return BUS_RESULT_TRUE;
-+    }
-+}
-+
-+static dbus_bool_t
-+bus_dispatch_test_check (const DBusString *test_data_dir)
-+{
-+  const char *filename = "valid-config-files/debug-check-some.conf";
-+  BusContext *context;
-+  DBusConnection *foo;
-+  DBusError error;
-+  dbus_bool_t result = TRUE;
-+  BusTestCheckData data;
-+
-+  /* save the config name for the activation helper */
-+  if (!setenv_TEST_LAUNCH_HELPER_CONFIG (test_data_dir, filename))
-+    _dbus_assert_not_reached ("no memory setting TEST_LAUNCH_HELPER_CONFIG");
-+
-+  dbus_error_init (&error);
-+
-+  context = bus_context_new_test (test_data_dir, filename);
-+  if (context == NULL)
-+    return FALSE;
-+
-+  foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
-+  if (foo == NULL)
-+    _dbus_assert_not_reached ("could not alloc connection");
-+
-+  if (!bus_setup_debug_client (foo))
-+    _dbus_assert_not_reached ("could not set up connection");
-+
-+  spin_connection_until_authenticated (context, foo);
-+
-+  if (!check_hello_message (context, foo))
-+    _dbus_assert_not_reached ("hello message failed");
-+
-+  if (!check_double_hello_message (context, foo))
-+    _dbus_assert_not_reached ("double hello message failed");
-+
-+  if (!check_add_match (context, foo, ""))
-+    _dbus_assert_not_reached ("AddMatch message failed");
-+
-+  /*
-+   * Cause bus_check_send_privilege() to return BUS_RESULT_LATER in the
-+   * first call, then BUS_RESULT_TRUE.
-+   */
-+  cdata = &data;
-+  memset (cdata, 0, sizeof(*cdata));
-+  bus_check_test_override = bus_dispatch_test_check_override;
-+
-+  result = check_existent_service_auto_start (context, foo);
-+
-+  _dbus_assert (cdata->check_counter == 2);
-+  _dbus_assert (cdata->timedout);
-+  _dbus_assert (cdata->timeout);
-+  _dbus_assert (!cdata->connection);
-+  _dbus_timeout_unref (cdata->timeout);
-+
-+  kill_client_connection_unchecked (foo);
-+
-+  bus_context_unref (context);
-+
-+  return result;
-+}
-+
- dbus_bool_t
- bus_dispatch_test (const DBusString *test_data_dir)
- {
-+  _dbus_verbose ("<check> tests\n");
-+  if (!bus_dispatch_test_check (test_data_dir))
-+    return FALSE;
-+
-   /* run normal activation tests */
-   _dbus_verbose ("Normal activation tests\n");
-   if (!bus_dispatch_test_conf (test_data_dir,
-diff --git a/bus/dispatch.h b/bus/dispatch.h
-index fb5ba7a..afba6a2 100644
---- a/bus/dispatch.h
-+++ b/bus/dispatch.h
-@@ -29,7 +29,7 @@
- dbus_bool_t bus_dispatch_add_connection    (DBusConnection *connection);
- void        bus_dispatch_remove_connection (DBusConnection *connection);
--dbus_bool_t bus_dispatch_matches           (BusTransaction *transaction,
-+BusResult   bus_dispatch_matches           (BusTransaction *transaction,
-                                             DBusConnection *sender,
-                                             DBusConnection *recipient,
-                                             DBusMessage    *message,
-diff --git a/bus/driver.c b/bus/driver.c
-index cd0a714..f414f64 100644
---- a/bus/driver.c
-+++ b/bus/driver.c
-@@ -218,6 +218,7 @@ bus_driver_send_service_owner_changed (const char     *service_name,
- {
-   DBusMessage *message;
-   dbus_bool_t retval;
-+  BusResult res;
-   const char *null_service;
-   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-@@ -253,7 +254,16 @@ bus_driver_send_service_owner_changed (const char     *service_name,
-   if (!bus_transaction_capture (transaction, NULL, NULL, message))
-     goto oom;
--  retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
-+  res = bus_dispatch_matches (transaction, NULL, NULL, message, error);
-+  if (res == BUS_RESULT_TRUE)
-+    retval = TRUE;
-+  else
-+    {
-+      retval = FALSE;
-+      if (res == BUS_RESULT_LATER)
-+        /* should never happen */
-+        _dbus_assert_not_reached ("bus_dispatch_matches returned BUS_RESULT_LATER unexpectedly");
-+    }
-   dbus_message_unref (message);
-   return retval;
-diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h
-index 4835732..94b1c95 100644
---- a/dbus/dbus-connection-internal.h
-+++ b/dbus/dbus-connection-internal.h
-@@ -118,6 +118,21 @@ DBUS_PRIVATE_EXPORT
- dbus_bool_t       _dbus_connection_get_linux_security_label       (DBusConnection  *connection,
-                                                                    char           **label_p);
-+DBUS_PRIVATE_EXPORT
-+void              _dbus_connection_enable_dispatch                (DBusConnection *connection);
-+DBUS_PRIVATE_EXPORT
-+void              _dbus_connection_disable_dispatch               (DBusConnection *connection);
-+
-+DBUS_PRIVATE_EXPORT
-+dbus_bool_t       _dbus_connection_putback_message                (DBusConnection *connection,
-+                                                                   DBusMessage    *after_message,
-+                                                                   DBusMessage    *message,
-+                                                                   DBusError      *error);
-+
-+DBUS_PRIVATE_EXPORT
-+dbus_bool_t       _dbus_connection_remove_message                 (DBusConnection *connection,
-+                                                                   DBusMessage    *message);
-+
- /* if DBUS_ENABLE_STATS */
- DBUS_PRIVATE_EXPORT
- void _dbus_connection_get_stats (DBusConnection *connection,
-diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
-index c525b6d..958968c 100644
---- a/dbus/dbus-connection.c
-+++ b/dbus/dbus-connection.c
-@@ -311,7 +311,8 @@ struct DBusConnection
-    */
-   dbus_bool_t dispatch_acquired; /**< Someone has dispatch path (can drain incoming queue) */
-   dbus_bool_t io_path_acquired;  /**< Someone has transport io path (can use the transport to read/write messages) */
--  
-+
-+  unsigned int dispatch_disabled : 1;  /**< if true, then dispatching incoming messages is stopped until enabled again */
-   unsigned int shareable : 1; /**< #TRUE if libdbus owns a reference to the connection and can return it from dbus_connection_open() more than once */
-   
-   unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */
-@@ -439,6 +440,39 @@ _dbus_connection_wakeup_mainloop (DBusConnection *connection)
-     (*connection->wakeup_main_function) (connection->wakeup_main_data);
- }
-+static void
-+_dbus_connection_set_dispatch(DBusConnection *connection,
-+                              dbus_bool_t disabled)
-+{
-+  CONNECTION_LOCK (connection);
-+  if (connection->dispatch_disabled != disabled)
-+    {
-+      DBusDispatchStatus status;
-+
-+      connection->dispatch_disabled = disabled;
-+      status = _dbus_connection_get_dispatch_status_unlocked (connection);
-+      _dbus_connection_update_dispatch_status_and_unlock (connection, status);
-+    }
-+  else
-+    {
-+      CONNECTION_UNLOCK (connection);
-+    }
-+}
-+
-+
-+void
-+_dbus_connection_enable_dispatch (DBusConnection *connection)
-+{
-+  _dbus_connection_set_dispatch (connection, FALSE);
-+}
-+
-+void
-+ _dbus_connection_disable_dispatch (DBusConnection *connection)
-+{
-+  _dbus_connection_set_dispatch (connection, TRUE);
-+}
-+
-+
- #ifdef DBUS_ENABLE_EMBEDDED_TESTS
- /**
-  * Gets the locks so we can examine them
-@@ -4069,6 +4103,82 @@ _dbus_connection_putback_message_link_unlocked (DBusConnection *connection,
-       "_dbus_connection_putback_message_link_unlocked");
- }
-+dbus_bool_t
-+_dbus_connection_putback_message (DBusConnection *connection,
-+                                  DBusMessage    *after_message,
-+                                  DBusMessage    *message,
-+                                  DBusError      *error)
-+{
-+  DBusDispatchStatus status;
-+  DBusList *message_link = _dbus_list_alloc_link (message);
-+  DBusList *after_link;
-+  if (message_link == NULL)
-+    {
-+      _DBUS_SET_OOM (error);
-+      return FALSE;
-+    }
-+  dbus_message_ref (message);
-+
-+  CONNECTION_LOCK (connection);
-+  _dbus_connection_acquire_dispatch (connection);
-+  HAVE_LOCK_CHECK (connection);
-+
-+  after_link = _dbus_list_find_first(&connection->incoming_messages, after_message);
-+  _dbus_list_insert_after_link (&connection->incoming_messages, after_link, message_link);
-+  connection->n_incoming += 1;
-+
-+  _dbus_verbose ("Message %p (%s %s %s '%s') put back into queue %p, %d incoming\n",
-+                 message_link->data,
-+                 dbus_message_type_to_string (dbus_message_get_type (message_link->data)),
-+                 dbus_message_get_interface (message_link->data) ?
-+                 dbus_message_get_interface (message_link->data) :
-+                 "no interface",
-+                 dbus_message_get_member (message_link->data) ?
-+                 dbus_message_get_member (message_link->data) :
-+                 "no member",
-+                 dbus_message_get_signature (message_link->data),
-+                 connection, connection->n_incoming);
-+
-+  _dbus_message_trace_ref (message_link->data, -1, -1,
-+      "_dbus_connection_putback_message");
-+
-+  _dbus_connection_release_dispatch (connection);
-+
-+  status = _dbus_connection_get_dispatch_status_unlocked (connection);
-+  _dbus_connection_update_dispatch_status_and_unlock (connection, status);
-+
-+  return TRUE;
-+}
-+
-+dbus_bool_t
-+_dbus_connection_remove_message (DBusConnection *connection,
-+                                 DBusMessage *message)
-+{
-+  DBusDispatchStatus status;
-+  dbus_bool_t removed;
-+
-+  CONNECTION_LOCK (connection);
-+  _dbus_connection_acquire_dispatch (connection);
-+  HAVE_LOCK_CHECK (connection);
-+
-+  removed = _dbus_list_remove(&connection->incoming_messages, message);
-+
-+  if (removed)
-+    {
-+      connection->n_incoming -= 1;
-+      dbus_message_unref(message);
-+      _dbus_verbose ("Message %p removed from incoming queue\n", message);
-+    }
-+  else
-+      _dbus_verbose ("Message %p not found in the incoming queue\n", message);
-+
-+  _dbus_connection_release_dispatch (connection);
-+
-+  status = _dbus_connection_get_dispatch_status_unlocked (connection);
-+  _dbus_connection_update_dispatch_status_and_unlock (connection, status);
-+  return removed;
-+}
-+
- /**
-  * Returns the first-received message from the incoming message queue,
-  * removing it from the queue. The caller owns a reference to the
-@@ -4252,8 +4362,9 @@ static DBusDispatchStatus
- _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection)
- {
-   HAVE_LOCK_CHECK (connection);
--  
--  if (connection->n_incoming > 0)
-+  if (connection->dispatch_disabled && _dbus_connection_get_is_connected_unlocked(connection))
-+    return DBUS_DISPATCH_COMPLETE;
-+  else if (connection->n_incoming > 0)
-     return DBUS_DISPATCH_DATA_REMAINS;
-   else if (!_dbus_transport_queue_messages (connection->transport))
-     return DBUS_DISPATCH_NEED_MEMORY;
-@@ -4716,6 +4827,8 @@ dbus_connection_dispatch (DBusConnection *connection)
-   
-   CONNECTION_LOCK (connection);
-+  if (result == DBUS_HANDLER_RESULT_LATER)
-+      goto out;
-   if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
-     {
-       _dbus_verbose ("No memory\n");
-@@ -4838,9 +4951,11 @@ dbus_connection_dispatch (DBusConnection *connection)
-                  connection);
-   
-  out:
--  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
-+  if (result == DBUS_HANDLER_RESULT_LATER ||
-+      result == DBUS_HANDLER_RESULT_NEED_MEMORY)
-     {
--      _dbus_verbose ("out of memory\n");
-+      if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
-+        _dbus_verbose ("out of memory\n");
-       
-       /* Put message back, and we'll start over.
-        * Yes this means handlers must be idempotent if they
-diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c
-index 8e713c0..32ea871 100644
---- a/dbus/dbus-list.c
-+++ b/dbus/dbus-list.c
-@@ -458,6 +458,35 @@ _dbus_list_remove_last (DBusList **list,
-     return FALSE;
- }
-+/**
-+ * Finds a value in the list. Returns the first link
-+ * with value equal to the given data pointer.
-+ * This is a linear-time operation.
-+ * Returns #NULL if no value found that matches.
-+ *
-+ * @param list address of the list head.
-+ * @param data the value to find.
-+ * @returns the link if found
-+ */
-+DBusList*
-+_dbus_list_find_first (DBusList **list,
-+                       void      *data)
-+{
-+  DBusList *link;
-+
-+  link = _dbus_list_get_first_link (list);
-+
-+  while (link != NULL)
-+    {
-+      if (link->data == data)
-+        return link;
-+
-+      link = _dbus_list_get_next_link (list, link);
-+    }
-+
-+  return NULL;
-+}
-+
- /**
-  * Finds a value in the list. Returns the last link
-  * with value equal to the given data pointer.
-diff --git a/dbus/dbus-list.h b/dbus/dbus-list.h
-index 9350a0d..fee9f1b 100644
---- a/dbus/dbus-list.h
-+++ b/dbus/dbus-list.h
-@@ -68,6 +68,9 @@ DBUS_PRIVATE_EXPORT
- void        _dbus_list_remove_link        (DBusList **list,
-                                            DBusList  *link);
- DBUS_PRIVATE_EXPORT
-+DBusList*   _dbus_list_find_first         (DBusList **list,
-+                                           void      *data);
-+DBUS_PRIVATE_EXPORT
- DBusList*   _dbus_list_find_last          (DBusList **list,
-                                            void      *data);
- DBUS_PRIVATE_EXPORT
-diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h
-index 7ab9103..e5bfbed 100644
---- a/dbus/dbus-shared.h
-+++ b/dbus/dbus-shared.h
-@@ -67,7 +67,8 @@ typedef enum
- {
-   DBUS_HANDLER_RESULT_HANDLED,         /**< Message has had its effect - no need to run more handlers. */ 
-   DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Message has not had any effect - see if other handlers want it. */
--  DBUS_HANDLER_RESULT_NEED_MEMORY      /**< Need more memory in order to return #DBUS_HANDLER_RESULT_HANDLED or #DBUS_HANDLER_RESULT_NOT_YET_HANDLED. Please try again later with more memory. */
-+  DBUS_HANDLER_RESULT_NEED_MEMORY,     /**< Need more memory in order to return #DBUS_HANDLER_RESULT_HANDLED or #DBUS_HANDLER_RESULT_NOT_YET_HANDLED. Please try again later with more memory. */
-+  DBUS_HANDLER_RESULT_LATER            /**< Message dispatch deferred due to pending policy check */
- } DBusHandlerResult;
- /* Bus names */
--- 
-2.21.1
-