diff options
Diffstat (limited to 'meta-security/recipes-core/dbus-cynara/dbus-cynara/0002-Disable-message-dispatching-when-send-rule-result-is.patch')
-rw-r--r-- | meta-security/recipes-core/dbus-cynara/dbus-cynara/0002-Disable-message-dispatching-when-send-rule-result-is.patch | 949 |
1 files changed, 0 insertions, 949 deletions
diff --git a/meta-security/recipes-core/dbus-cynara/dbus-cynara/0002-Disable-message-dispatching-when-send-rule-result-is.patch b/meta-security/recipes-core/dbus-cynara/dbus-cynara/0002-Disable-message-dispatching-when-send-rule-result-is.patch deleted file mode 100644 index ebbd531ff..000000000 --- a/meta-security/recipes-core/dbus-cynara/dbus-cynara/0002-Disable-message-dispatching-when-send-rule-result-is.patch +++ /dev/null @@ -1,949 +0,0 @@ -From aae977a0c4bb1c25640c7056166fbc4e76ef1db6 Mon Sep 17 00:00:00 2001 -From: Jacek Bukarewicz <j.bukarewicz@samsung.com> -Date: Fri, 28 Nov 2014 12:07:39 +0100 -Subject: 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> - -diff --git a/bus/activation.c b/bus/activation.c -index f8a02eb..005047f 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,9 +1272,40 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation - bus_connection_send_oom_error (entry->connection, - entry->activation_message); - } -+ } -+ 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; -+ } - -- 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); -+ } - } - } - -@@ -1286,6 +1323,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; - } - -@@ -2078,6 +2128,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, -@@ -2085,8 +2136,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.17.2 - |