Prepare master for new framework integration
[AGL/meta-agl.git] / meta-app-framework / recipes-core / dbus-cynagora / dbus-cynagora / 0001-Integration-of-Cynara-asynchronous-security-checks.patch
diff --git a/meta-app-framework/recipes-core/dbus-cynagora/dbus-cynagora/0001-Integration-of-Cynara-asynchronous-security-checks.patch b/meta-app-framework/recipes-core/dbus-cynagora/dbus-cynagora/0001-Integration-of-Cynara-asynchronous-security-checks.patch
deleted file mode 100644 (file)
index 55cedb9..0000000
+++ /dev/null
@@ -1,2309 +0,0 @@
-From ea4b650366261e4257e4b0fb95e7f48e30ef36f0 Mon Sep 17 00:00:00 2001
-From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
-Date: Thu, 27 Nov 2014 18:11:05 +0100
-Subject: [PATCH 1/8] Integration of Cynara asynchronous security checks
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This commit introduces basic framework for asynchronous policy
-checks and Cynara integration code. Functions for checking security
-policy can now return third value - BUS_RESULT_LATER denoting check
-result unavailability. Whenever policy checker cannot decide on the
-result of the check it is supposed to allocate DeferredMessage structure
-that will be passed to the upper layers which can decide what should be
-done in such situation.
-Proper handling of such case will be implemented in subsequent commits.
-Currently such return value results in message denial.
-
-Cherry picked from 4dcfb02f17247ff9de966b62182cd2e08f301238
-by José Bollo.
-
-Updated for dbus 1.10.20 by Scott Murray and José Bollo
-Updated for dbus 1.12.16 by José Bollo
-
-Change-Id: I9bcbce34577e5dc2a3cecf6233a0a2b0e43e1108
-Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-Signed-off-by: Scott Murray <scott.murray@konsulko.com>
----
- bus/Makefile.am                               |   6 +
- bus/activation.c                              |   5 +-
- bus/bus.c                                     | 124 ++++--
- bus/bus.h                                     |  22 +-
- bus/check.c                                   | 217 ++++++++++
- bus/check.h                                   |  68 ++++
- bus/config-parser-common.c                    |   6 +
- bus/config-parser-common.h                    |   1 +
- bus/config-parser-trivial.c                   |   2 +
- bus/config-parser.c                           |  72 +++-
- bus/connection.c                              |  57 ++-
- bus/connection.h                              |   4 +
- bus/cynara.c                                  | 374 ++++++++++++++++++
- bus/cynara.h                                  |  37 ++
- bus/dispatch.c                                |  46 ++-
- bus/driver.h                                  |   2 +
- bus/policy.c                                  | 195 ++++++---
- bus/policy.h                                  |  29 +-
- configure.ac                                  |  12 +
- test/Makefile.am                              |   1 +
- .../data/invalid-config-files/badcheck-1.conf |   9 +
- .../data/invalid-config-files/badcheck-2.conf |   9 +
- test/data/valid-config-files/check-1.conf     |   9 +
- .../debug-check-some.conf.in                  |  18 +
- 24 files changed, 1181 insertions(+), 144 deletions(-)
- create mode 100644 bus/check.c
- create mode 100644 bus/check.h
- create mode 100644 bus/cynara.c
- create mode 100644 bus/cynara.h
- create mode 100644 test/data/invalid-config-files/badcheck-1.conf
- create mode 100644 test/data/invalid-config-files/badcheck-2.conf
- create mode 100644 test/data/valid-config-files/check-1.conf
- create mode 100644 test/data/valid-config-files/debug-check-some.conf.in
-
-diff --git a/bus/Makefile.am b/bus/Makefile.am
-index c917063..2a8a72c 100644
---- a/bus/Makefile.am
-+++ b/bus/Makefile.am
-@@ -13,6 +13,7 @@ DBUS_BUS_LIBS = \
-       $(THREAD_LIBS) \
-       $(ADT_LIBS) \
-       $(NETWORK_libs) \
-+      $(CYNARA_LIBS) \
-       $(NULL)
- DBUS_LAUNCHER_LIBS = \
-@@ -30,6 +31,7 @@ AM_CPPFLAGS = \
-       $(APPARMOR_CFLAGS) \
-       -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \
-       -DDBUS_COMPILATION \
-+      $(CYNARA_CFLAGS) \
-       $(NULL)
- # if assertions are enabled, improve backtraces
-@@ -90,6 +92,8 @@ BUS_SOURCES=                                 \
-       audit.h                                 \
-       bus.c                                   \
-       bus.h                                   \
-+      check.c                                 \
-+      check.h                                 \
-       config-loader-expat.c                   \
-       config-parser.c                         \
-       config-parser.h                         \
-@@ -97,6 +101,8 @@ BUS_SOURCES=                                        \
-       config-parser-common.h                  \
-       connection.c                            \
-       connection.h                            \
-+      cynara.c                                \
-+      cynara.h                                \
-       desktop-file.c                          \
-       desktop-file.h                          \
-       $(DIR_WATCH_SOURCE)                     \
-diff --git a/bus/activation.c b/bus/activation.c
-index 99404b9..f9c6c62 100644
---- a/bus/activation.c
-+++ b/bus/activation.c
-@@ -1789,14 +1789,15 @@ bus_activation_activate_service (BusActivation  *activation,
-   if (auto_activation &&
-       entry != NULL &&
--      !bus_context_check_security_policy (activation->context,
-+      BUS_RESULT_TRUE != bus_context_check_security_policy (activation->context,
-         transaction,
-         connection, /* sender */
-         NULL, /* addressed recipient */
-         NULL, /* proposed recipient */
-         activation_message,
-         entry,
--        error))
-+        error,
-+        NULL))
-     {
-       _DBUS_ASSERT_ERROR_IS_SET (error);
-       _dbus_verbose ("activation not authorized: %s: %s\n",
-diff --git a/bus/bus.c b/bus/bus.c
-index 2ad8e78..6fc45d0 100644
---- a/bus/bus.c
-+++ b/bus/bus.c
-@@ -38,6 +38,7 @@
- #include "apparmor.h"
- #include "audit.h"
- #include "dir-watch.h"
-+#include "check.h"
- #include <dbus/dbus-auth.h>
- #include <dbus/dbus-list.h>
- #include <dbus/dbus-hash.h>
-@@ -67,6 +68,7 @@ struct BusContext
-   BusRegistry *registry;
-   BusPolicy *policy;
-   BusMatchmaker *matchmaker;
-+  BusCheck *check;
-   BusLimits limits;
-   DBusRLimit *initial_fd_limit;
-   unsigned int fork : 1;
-@@ -1003,6 +1005,10 @@ bus_context_new (const DBusString *config_file,
-       parser = NULL;
-     }
-+  context->check = bus_check_new(context, error);
-+  if (context->check == NULL)
-+      goto failed;
-+
-   dbus_server_free_data_slot (&server_data_slot);
-   return context;
-@@ -1127,6 +1133,12 @@ bus_context_unref (BusContext *context)
-       bus_context_shutdown (context);
-+      if (context->check)
-+        {
-+          bus_check_unref(context->check);
-+          context->check = NULL;
-+        }
-+
-       if (context->connections)
-         {
-           bus_connections_unref (context->connections);
-@@ -1256,6 +1268,12 @@ bus_context_get_loop (BusContext *context)
-   return context->loop;
- }
-+BusCheck*
-+bus_context_get_check (BusContext *context)
-+{
-+  return context->check;
-+}
-+
- dbus_bool_t
- bus_context_allow_unix_user (BusContext   *context,
-                              unsigned long uid)
-@@ -1451,6 +1469,7 @@ complain_about_message (BusContext     *context,
-                         DBusConnection *proposed_recipient,
-                         dbus_bool_t     requested_reply,
-                         dbus_bool_t     log,
-+                        const char     *privilege,
-                         DBusError      *error)
- {
-   DBusError stack_error = DBUS_ERROR_INIT;
-@@ -1480,7 +1499,8 @@ complain_about_message (BusContext     *context,
-   dbus_set_error (&stack_error, error_name,
-       "%s, %d matched rules; type=\"%s\", sender=\"%s\" (%s) "
-       "interface=\"%s\" member=\"%s\" error name=\"%s\" "
--      "requested_reply=\"%d\" destination=\"%s\" (%s)",
-+      "requested_reply=\"%d\" destination=\"%s\" (%s) "
-+      "privilege=\"%s\"",
-       complaint,
-       matched_rules,
-       dbus_message_type_to_string (dbus_message_get_type (message)),
-@@ -1491,7 +1511,8 @@ complain_about_message (BusContext     *context,
-       nonnull (dbus_message_get_error_name (message), "(unset)"),
-       requested_reply,
-       nonnull (dbus_message_get_destination (message), DBUS_SERVICE_DBUS),
--      proposed_recipient_loginfo);
-+      proposed_recipient_loginfo,
-+      nonnull (privilege, "(n/a)"));
-   /* If we hit OOM while setting the error, this will syslog "out of memory"
-    * which is itself an indication that something is seriously wrong */
-@@ -1519,7 +1540,7 @@ complain_about_message (BusContext     *context,
-  * NULL for addressed_recipient may mean the bus driver, or may mean
-  * no destination was specified in the message (e.g. a signal).
-  */
--dbus_bool_t
-+BusResult
- bus_context_check_security_policy (BusContext     *context,
-                                    BusTransaction *transaction,
-                                    DBusConnection *sender,
-@@ -1527,7 +1548,8 @@ bus_context_check_security_policy (BusContext     *context,
-                                    DBusConnection *proposed_recipient,
-                                    DBusMessage    *message,
-                                    BusActivationEntry *activation_entry,
--                                   DBusError      *error)
-+                                   DBusError      *error,
-+                                   BusDeferredMessage **deferred_message)
- {
-   const char *src, *dest;
-   BusClientPolicy *sender_policy;
-@@ -1536,6 +1558,7 @@ bus_context_check_security_policy (BusContext     *context,
-   dbus_bool_t log;
-   int type;
-   dbus_bool_t requested_reply;
-+  const char *privilege;
-   type = dbus_message_get_type (message);
-   src = dbus_message_get_sender (message);
-@@ -1565,7 +1588,7 @@ bus_context_check_security_policy (BusContext     *context,
-       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
-                       "Message bus will not accept messages of unknown type\n");
--      return FALSE;
-+      return BUS_RESULT_FALSE;
-     }
-   requested_reply = FALSE;
-@@ -1595,7 +1618,7 @@ bus_context_check_security_policy (BusContext     *context,
-                   if (dbus_error_is_set (&error2))
-                     {
-                       dbus_move_error (&error2, error);
--                      return FALSE;
-+                      return BUS_RESULT_FALSE;
-                     }
-                 }
-             }
-@@ -1624,11 +1647,11 @@ bus_context_check_security_policy (BusContext     *context,
-               complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
-                   "An SELinux policy prevents this sender from sending this "
-                   "message to this recipient",
--                  0, message, sender, proposed_recipient, FALSE, FALSE, error);
-+                  0, message, sender, proposed_recipient, FALSE, FALSE, NULL, error);
-               _dbus_verbose ("SELinux security check denying send to service\n");
-             }
--          return FALSE;
-+          return BUS_RESULT_FALSE;
-         }
-       /* next verify AppArmor access controls.  If allowed then
-@@ -1646,7 +1669,7 @@ bus_context_check_security_policy (BusContext     *context,
-                                      src ? src : DBUS_SERVICE_DBUS,
-                                      activation_entry,
-                                      error))
--        return FALSE;
-+        return BUS_RESULT_FALSE;
-       if (!bus_connection_is_active (sender))
-         {
-@@ -1660,7 +1683,7 @@ bus_context_check_security_policy (BusContext     *context,
-             {
-               _dbus_verbose ("security check allowing %s message\n",
-                              "Hello");
--              return TRUE;
-+              return BUS_RESULT_TRUE;
-             }
-           else
-             {
-@@ -1671,7 +1694,7 @@ bus_context_check_security_policy (BusContext     *context,
-                               "Client tried to send a message other than %s without being registered",
-                               "Hello");
--              return FALSE;
-+              return BUS_RESULT_FALSE;
-             }
-         }
-     }
-@@ -1720,20 +1743,29 @@ bus_context_check_security_policy (BusContext     *context,
-                 (proposed_recipient == NULL && recipient_policy == NULL));
-   log = FALSE;
--  if (sender_policy &&
--      !bus_client_policy_check_can_send (sender_policy,
--                                         context->registry,
--                                         requested_reply,
--                                         proposed_recipient,
--                                         message, &toggles, &log))
--    {
--      complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
--          "Rejected send message", toggles,
--          message, sender, proposed_recipient, requested_reply,
--          (addressed_recipient == proposed_recipient), error);
--      _dbus_verbose ("security policy disallowing message due to sender policy\n");
--      return FALSE;
--    }
-+  if (sender_policy)
-+    {
-+      BusResult res = bus_client_policy_check_can_send (sender,
-+                                                        sender_policy,
-+                                                        context->registry,
-+                                                        requested_reply,
-+                                                        addressed_recipient,
-+                                                        proposed_recipient,
-+                                                        message, &toggles, &log, &privilege,
-+                                                        deferred_message);
-+      if (res == BUS_RESULT_FALSE)
-+        {
-+          complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
-+                                  "Rejected send message", toggles,
-+                                  message, sender, proposed_recipient, requested_reply,
-+                                  (addressed_recipient == proposed_recipient), privilege,
-+                                  error);
-+          _dbus_verbose ("security policy disallowing message due to sender policy\n");
-+          return BUS_RESULT_FALSE;
-+        }
-+      else if (res == BUS_RESULT_LATER)
-+        return BUS_RESULT_LATER;
-+  }
-   if (log)
-     {
-@@ -1742,23 +1774,29 @@ bus_context_check_security_policy (BusContext     *context,
-       complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
-           "Would reject message", toggles,
-           message, sender, proposed_recipient, requested_reply,
--          TRUE, NULL);
-+          TRUE, privilege, NULL);
-     }
--  if (recipient_policy &&
--      !bus_client_policy_check_can_receive (recipient_policy,
--                                            context->registry,
--                                            requested_reply,
--                                            sender,
--                                            addressed_recipient, proposed_recipient,
--                                            message, &toggles))
-+  if (recipient_policy)
-     {
--      complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
--          "Rejected receive message", toggles,
--          message, sender, proposed_recipient, requested_reply,
--          (addressed_recipient == proposed_recipient), error);
--      _dbus_verbose ("security policy disallowing message due to recipient policy\n");
--      return FALSE;
-+      BusResult res;
-+      res = bus_client_policy_check_can_receive (recipient_policy,
-+                                                 context->registry,
-+                                                 requested_reply,
-+                                                 sender,
-+                                                 addressed_recipient, proposed_recipient,
-+                                                 message, &toggles, &privilege, deferred_message);
-+      if (res == BUS_RESULT_FALSE)
-+        {
-+          complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected receive message",
-+              toggles, message, sender, proposed_recipient, requested_reply,
-+            (addressed_recipient == proposed_recipient), privilege, error);
-+          _dbus_verbose(
-+            "security policy disallowing message due to recipient policy\n");
-+          return BUS_RESULT_FALSE;
-+        }
-+      else if (res == BUS_RESULT_LATER)
-+        return BUS_RESULT_LATER;
-     }
-   /* See if limits on size have been exceeded */
-@@ -1768,10 +1806,10 @@ bus_context_check_security_policy (BusContext     *context,
-     {
-       complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
-           "Rejected: destination has a full message queue",
--          0, message, sender, proposed_recipient, requested_reply, TRUE,
-+          0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
-           error);
-       _dbus_verbose ("security policy disallowing message due to full message queue\n");
--      return FALSE;
-+      return BUS_RESULT_FALSE;
-     }
-   /* Record that we will allow a reply here in the future (don't
-@@ -1792,11 +1830,11 @@ bus_context_check_security_policy (BusContext     *context,
-                                      message, error))
-     {
-       _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
--      return FALSE;
-+      return BUS_RESULT_FALSE;
-     }
-   _dbus_verbose ("security policy allowing message\n");
--  return TRUE;
-+  return BUS_RESULT_TRUE;
- }
- void
-diff --git a/bus/bus.h b/bus/bus.h
-index 2e0de82..82c32c8 100644
---- a/bus/bus.h
-+++ b/bus/bus.h
-@@ -45,6 +45,22 @@ typedef struct BusTransaction   BusTransaction;
- typedef struct BusMatchmaker    BusMatchmaker;
- typedef struct BusMatchRule     BusMatchRule;
- typedef struct BusActivationEntry BusActivationEntry;
-+typedef struct BusCheck         BusCheck;
-+typedef struct BusDeferredMessage BusDeferredMessage;
-+typedef struct BusCynara        BusCynara;
-+
-+/**
-+ * BusResult is defined as a pointer to a dummy structure to allow detection of type mismatches.
-+ * The disadvantage of such solution is that now BusResult variables cannot be used in switch
-+ * statement.
-+ * Additionally, BUS_RESULT_TRUE is defined as 0 instead of 1 to help detect type mismatches
-+ * at runtime.
-+ */
-+typedef const struct BusResultStruct { int dummy; } *BusResult;
-+
-+static const BusResult BUS_RESULT_TRUE  = (BusResult)0x0;
-+static const BusResult BUS_RESULT_FALSE = (BusResult)0x1;
-+static const BusResult BUS_RESULT_LATER = (BusResult)0x2;
- typedef struct
- {
-@@ -101,6 +117,7 @@ BusConnections*   bus_context_get_connections                    (BusContext
- BusActivation*    bus_context_get_activation                     (BusContext       *context);
- BusMatchmaker*    bus_context_get_matchmaker                     (BusContext       *context);
- DBusLoop*         bus_context_get_loop                           (BusContext       *context);
-+BusCheck *        bus_context_get_check                          (BusContext       *context);
- dbus_bool_t       bus_context_allow_unix_user                    (BusContext       *context,
-                                                                   unsigned long     uid);
- dbus_bool_t       bus_context_allow_windows_user                 (BusContext       *context,
-@@ -136,14 +153,15 @@ void              bus_context_log_and_set_error                  (BusContext
-                                                                   const char       *name,
-                                                                   const char       *msg,
-                                                                   ...) _DBUS_GNUC_PRINTF (5, 6);
--dbus_bool_t       bus_context_check_security_policy              (BusContext       *context,
-+BusResult         bus_context_check_security_policy              (BusContext       *context,
-                                                                   BusTransaction   *transaction,
-                                                                   DBusConnection   *sender,
-                                                                   DBusConnection   *addressed_recipient,
-                                                                   DBusConnection   *proposed_recipient,
-                                                                   DBusMessage      *message,
-                                                                   BusActivationEntry *activation_entry,
--                                                                  DBusError        *error);
-+                                                                  DBusError        *error,
-+                                                                  BusDeferredMessage **deferred_message);
- void              bus_context_check_all_watches                  (BusContext       *context);
- #endif /* BUS_BUS_H */
-diff --git a/bus/check.c b/bus/check.c
-new file mode 100644
-index 0000000..5b72d31
---- /dev/null
-+++ b/bus/check.c
-@@ -0,0 +1,217 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* check.c  Bus security policy runtime check
-+ *
-+ * Copyright (C) 2014  Intel, Inc.
-+ * Copyright (c) 2014  Samsung Electronics, Ltd.
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-+ *
-+ */
-+
-+#include <config.h>
-+#include "check.h"
-+#include "connection.h"
-+#include "dispatch.h"
-+#include "cynara.h"
-+#include "utils.h"
-+#include <dbus/dbus-connection-internal.h>
-+#include <dbus/dbus-message-internal.h>
-+#include <dbus/dbus-internals.h>
-+
-+
-+typedef struct BusCheck
-+{
-+  int refcount;
-+
-+  BusContext *context;
-+  BusCynara *cynara;
-+} BusCheck;
-+
-+typedef struct BusDeferredMessage
-+{
-+  int refcount;
-+
-+  DBusMessage *message;
-+  DBusConnection *sender;
-+  DBusConnection *proposed_recipient;
-+  DBusConnection *addressed_recipient;
-+  dbus_bool_t full_dispatch;
-+  BusDeferredMessageStatus status;
-+  BusResult response;
-+  BusCheckResponseFunc response_callback;
-+} BusDeferredMessage;
-+
-+BusCheck *
-+bus_check_new (BusContext *context, DBusError *error)
-+{
-+  BusCheck *check;
-+
-+  check = dbus_new(BusCheck, 1);
-+  if (check == NULL)
-+    {
-+      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_free(check);
-+      return NULL;
-+    }
-+
-+  return check;
-+}
-+
-+BusCheck *
-+bus_check_ref (BusCheck *check)
-+{
-+  _dbus_assert (check->refcount > 0);
-+  check->refcount += 1;
-+
-+  return check;
-+}
-+
-+void
-+bus_check_unref (BusCheck *check)
-+{
-+  _dbus_assert (check->refcount > 0);
-+
-+  check->refcount -= 1;
-+
-+  if (check->refcount == 0)
-+    {
-+      bus_cynara_unref(check->cynara);
-+      dbus_free(check);
-+    }
-+}
-+
-+BusContext *
-+bus_check_get_context (BusCheck *check)
-+{
-+  return check->context;
-+}
-+
-+BusCynara *
-+bus_check_get_cynara (BusCheck *check)
-+{
-+  return check->cynara;
-+}
-+
-+BusResult
-+bus_check_privilege (BusCheck *check,
-+                     DBusMessage *message,
-+                     DBusConnection *sender,
-+                     DBusConnection *addressed_recipient,
-+                     DBusConnection *proposed_recipient,
-+                     const char *privilege,
-+                     BusDeferredMessageStatus check_type,
-+                     BusDeferredMessage **deferred_message)
-+{
-+  BusResult result = BUS_RESULT_FALSE;
-+#ifdef DBUS_ENABLE_CYNARA
-+  BusCynara *cynara;
-+#endif
-+  DBusConnection *connection;
-+
-+  connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
-+
-+  if (!dbus_connection_get_is_connected(connection))
-+    {
-+      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);
-+#endif
-+
-+  if (result == BUS_RESULT_LATER && deferred_message != NULL)
-+    {
-+      (*deferred_message)->status |= check_type;
-+    }
-+  return result;
-+}
-+
-+BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
-+                                              DBusConnection *sender,
-+                                              DBusConnection *addressed_recipient,
-+                                              DBusConnection *proposed_recipient,
-+                                              BusResult response)
-+{
-+  BusDeferredMessage *deferred_message;
-+
-+  deferred_message = dbus_new(BusDeferredMessage, 1);
-+  if (deferred_message == NULL)
-+    {
-+      return NULL;
-+    }
-+
-+  deferred_message->refcount = 1;
-+  deferred_message->sender = sender != NULL ? dbus_connection_ref(sender) : NULL;
-+  deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
-+  deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
-+  deferred_message->message = dbus_message_ref(message);
-+  deferred_message->response = response;
-+  deferred_message->status = 0;
-+  deferred_message->full_dispatch = FALSE;
-+  deferred_message->response_callback = NULL;
-+
-+  return deferred_message;
-+}
-+
-+BusDeferredMessage *
-+bus_deferred_message_ref (BusDeferredMessage *deferred_message)
-+{
-+  _dbus_assert (deferred_message->refcount > 0);
-+  deferred_message->refcount += 1;
-+  return deferred_message;
-+}
-+
-+void
-+bus_deferred_message_unref (BusDeferredMessage *deferred_message)
-+{
-+  _dbus_assert (deferred_message->refcount > 0);
-+
-+  deferred_message->refcount -= 1;
-+
-+   if (deferred_message->refcount == 0)
-+     {
-+       dbus_message_unref(deferred_message->message);
-+       if (deferred_message->sender != NULL)
-+           dbus_connection_unref(deferred_message->sender);
-+       if (deferred_message->addressed_recipient != NULL)
-+           dbus_connection_unref(deferred_message->addressed_recipient);
-+       if (deferred_message->proposed_recipient != NULL)
-+           dbus_connection_unref(deferred_message->proposed_recipient);
-+       dbus_free(deferred_message);
-+     }
-+}
-+
-+void
-+bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
-+                                        BusResult result)
-+{
-+  if (deferred_message->response_callback != NULL)
-+    {
-+      deferred_message->response_callback(deferred_message, result);
-+    }
-+}
-diff --git a/bus/check.h b/bus/check.h
-new file mode 100644
-index 0000000..c3fcaf9
---- /dev/null
-+++ b/bus/check.h
-@@ -0,0 +1,68 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* check.h  Bus security policy runtime check
-+ *
-+ * Copyright (C) 2014  Intel, Inc.
-+ * Copyright (c) 2014  Samsung Electronics, Ltd.
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-+ *
-+ */
-+
-+#ifndef BUS_CHECK_H
-+#define BUS_CHECK_H
-+
-+#include "bus.h"
-+#include "policy.h"
-+
-+
-+typedef void (*BusCheckResponseFunc) (BusDeferredMessage *message,
-+                                      BusResult result);
-+
-+typedef enum {
-+  BUS_DEFERRED_MESSAGE_CHECK_SEND      = 1 << 0,
-+  BUS_DEFERRED_MESSAGE_CHECK_RECEIVE   = 1 << 1,
-+  BUS_DEFERRED_MESSAGE_CHECK_OWN       = 1 << 2,
-+} BusDeferredMessageStatus;
-+
-+
-+BusCheck   *bus_check_new         (BusContext *context,
-+                                   DBusError *error);
-+BusCheck   *bus_check_ref         (BusCheck *check);
-+void        bus_check_unref       (BusCheck *check);
-+
-+BusContext *bus_check_get_context (BusCheck *check);
-+BusCynara  *bus_check_get_cynara  (BusCheck *check);
-+BusResult   bus_check_privilege   (BusCheck *check,
-+                                   DBusMessage *message,
-+                                   DBusConnection *sender,
-+                                   DBusConnection *addressed_recipient,
-+                                   DBusConnection *proposed_recipient,
-+                                   const char *privilege,
-+                                   BusDeferredMessageStatus check_type,
-+                                   BusDeferredMessage **deferred_message);
-+
-+BusDeferredMessage *bus_deferred_message_new                (DBusMessage *message,
-+                                                             DBusConnection *sender,
-+                                                             DBusConnection *addressed_recipient,
-+                                                             DBusConnection *proposed_recipient,
-+                                                             BusResult response);
-+
-+BusDeferredMessage *bus_deferred_message_ref                (BusDeferredMessage *deferred_message);
-+void                bus_deferred_message_unref              (BusDeferredMessage *deferred_message);
-+void                bus_deferred_message_response_received  (BusDeferredMessage *deferred_message,
-+                                                             BusResult result);
-+#endif /* BUS_CHECK_H */
-diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
-index c1c4191..e2f253d 100644
---- a/bus/config-parser-common.c
-+++ b/bus/config-parser-common.c
-@@ -75,6 +75,10 @@ bus_config_parser_element_name_to_type (const char *name)
-     {
-       return ELEMENT_DENY;
-     }
-+  else if (strcmp (name, "check") == 0)
-+    {
-+      return ELEMENT_CHECK;
-+    }
-   else if (strcmp (name, "servicehelper") == 0)
-     {
-       return ELEMENT_SERVICEHELPER;
-@@ -159,6 +163,8 @@ bus_config_parser_element_type_to_name (ElementType type)
-       return "allow";
-     case ELEMENT_DENY:
-       return "deny";
-+    case ELEMENT_CHECK:
-+      return "check";
-     case ELEMENT_FORK:
-       return "fork";
-     case ELEMENT_PIDFILE:
-diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
-index 382a014..9e026d1 100644
---- a/bus/config-parser-common.h
-+++ b/bus/config-parser-common.h
-@@ -36,6 +36,7 @@ typedef enum
-   ELEMENT_LIMIT,
-   ELEMENT_ALLOW,
-   ELEMENT_DENY,
-+  ELEMENT_CHECK,
-   ELEMENT_FORK,
-   ELEMENT_PIDFILE,
-   ELEMENT_SERVICEDIR,
-diff --git a/bus/config-parser-trivial.c b/bus/config-parser-trivial.c
-index dd65c6d..23dedb4 100644
---- a/bus/config-parser-trivial.c
-+++ b/bus/config-parser-trivial.c
-@@ -194,6 +194,7 @@ bus_config_parser_start_element (BusConfigParser   *parser,
-     case ELEMENT_POLICY:
-     case ELEMENT_LIMIT:
-     case ELEMENT_ALLOW:
-+    case ELEMENT_CHECK:
-     case ELEMENT_DENY:
-     case ELEMENT_FORK:
-     case ELEMENT_PIDFILE:
-@@ -316,6 +317,7 @@ bus_config_parser_content (BusConfigParser   *parser,
-     case ELEMENT_POLICY:
-     case ELEMENT_LIMIT:
-     case ELEMENT_ALLOW:
-+    case ELEMENT_CHECK:
-     case ELEMENT_DENY:
-     case ELEMENT_FORK:
-     case ELEMENT_PIDFILE:
-diff --git a/bus/config-parser.c b/bus/config-parser.c
-index be27d38..7f91469 100644
---- a/bus/config-parser.c
-+++ b/bus/config-parser.c
-@@ -1318,7 +1318,7 @@ append_rule_from_element (BusConfigParser   *parser,
-                           const char        *element_name,
-                           const char       **attribute_names,
-                           const char       **attribute_values,
--                          dbus_bool_t        allow,
-+                          BusPolicyRuleAccess access,
-                           DBusError         *error)
- {
-   const char *log;
-@@ -1360,6 +1360,7 @@ append_rule_from_element (BusConfigParser   *parser,
-   const char *own_prefix;
-   const char *user;
-   const char *group;
-+  const char *privilege;
-   BusPolicyRule *rule;
-@@ -1390,6 +1391,7 @@ append_rule_from_element (BusConfigParser   *parser,
-                           "user", &user,
-                           "group", &group,
-                           "log", &log,
-+                          "privilege", &privilege,
-                           NULL))
-     return FALSE;
-@@ -1422,6 +1424,7 @@ append_rule_from_element (BusConfigParser   *parser,
-   if (!(any_send_attribute ||
-         any_receive_attribute ||
-+        privilege ||
-         own || own_prefix || user || group))
-     {
-       dbus_set_error (error, DBUS_ERROR_FAILED,
-@@ -1438,7 +1441,30 @@ append_rule_from_element (BusConfigParser   *parser,
-                       element_name);
-       return FALSE;
-     }
--  
-+
-+  if (access == BUS_POLICY_RULE_ACCESS_CHECK)
-+    {
-+      if (privilege == NULL || !*privilege)
-+        {
-+          dbus_set_error (error, DBUS_ERROR_FAILED,
-+                          "On element <%s>, you must specify the privilege to be checked.",
-+                          element_name);
-+          return FALSE;
-+        }
-+    }
-+  else
-+    {
-+      if (privilege != NULL && *privilege)
-+        {
-+          dbus_set_error (error, DBUS_ERROR_FAILED,
-+                          "On element <%s>, privilege %s is used outside of a check rule.",
-+                          element_name, privilege);
-+          return FALSE;
-+        }
-+      else
-+        privilege = NULL; /* replace (potentially) empty string with NULL pointer, it wouldn't be used anyway */
-+    }
-+
-   /* Allowed combinations of elements are:
-    *
-    *   base, must be all send or all receive:
-@@ -1589,7 +1615,7 @@ append_rule_from_element (BusConfigParser   *parser,
-                                 error))
-         return FALSE;
--      rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); 
-+      rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, access);
-       if (rule == NULL)
-         goto nomem;
-       
-@@ -1694,7 +1720,7 @@ append_rule_from_element (BusConfigParser   *parser,
-                                 error))
-         return FALSE;
--      rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); 
-+      rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, access);
-       if (rule == NULL)
-         goto nomem;
-@@ -1726,7 +1752,7 @@ append_rule_from_element (BusConfigParser   *parser,
-     }
-   else if (own || own_prefix)
-     {
--      rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 
-+      rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, access);
-       if (rule == NULL)
-         goto nomem;
-@@ -1752,7 +1778,7 @@ append_rule_from_element (BusConfigParser   *parser,
-     {      
-       if (IS_WILDCARD (user))
-         {
--          rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
-+          rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
-           if (rule == NULL)
-             goto nomem;
-@@ -1767,7 +1793,7 @@ append_rule_from_element (BusConfigParser   *parser,
-       
-           if (_dbus_parse_unix_user_from_config (&username, &uid))
-             {
--              rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
-+              rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
-               if (rule == NULL)
-                 goto nomem;
-@@ -1784,7 +1810,7 @@ append_rule_from_element (BusConfigParser   *parser,
-     {
-       if (IS_WILDCARD (group))
-         {
--          rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
-+          rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
-           if (rule == NULL)
-             goto nomem;
-@@ -1799,7 +1825,7 @@ append_rule_from_element (BusConfigParser   *parser,
-           
-           if (_dbus_parse_unix_group_from_config (&groupname, &gid))
-             {
--              rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
-+              rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
-               if (rule == NULL)
-                 goto nomem;
-@@ -1823,6 +1849,10 @@ append_rule_from_element (BusConfigParser   *parser,
-       _dbus_assert (pe != NULL);
-       _dbus_assert (pe->type == ELEMENT_POLICY);
-+      rule->privilege = _dbus_strdup (privilege);
-+      if (privilege && !rule->privilege)
-+        goto nomem;
-+
-       switch (pe->d.policy.type)
-         {
-         case POLICY_IGNORED:
-@@ -1898,7 +1928,7 @@ start_policy_child (BusConfigParser   *parser,
-     {
-       if (!append_rule_from_element (parser, element_name,
-                                      attribute_names, attribute_values,
--                                     TRUE, error))
-+                                     BUS_POLICY_RULE_ACCESS_ALLOW, error))
-         return FALSE;
-       
-       if (push_element (parser, ELEMENT_ALLOW) == NULL)
-@@ -1913,7 +1943,7 @@ start_policy_child (BusConfigParser   *parser,
-     {
-       if (!append_rule_from_element (parser, element_name,
-                                      attribute_names, attribute_values,
--                                     FALSE, error))
-+                                     BUS_POLICY_RULE_ACCESS_DENY, error))
-         return FALSE;
-       
-       if (push_element (parser, ELEMENT_DENY) == NULL)
-@@ -1922,6 +1952,21 @@ start_policy_child (BusConfigParser   *parser,
-           return FALSE;
-         }
-       
-+      return TRUE;
-+    }
-+  else if (strcmp (element_name, "check") == 0)
-+    {
-+      if (!append_rule_from_element (parser, element_name,
-+                                     attribute_names, attribute_values,
-+                                     BUS_POLICY_RULE_ACCESS_CHECK, error))
-+        return FALSE;
-+
-+      if (push_element (parser, ELEMENT_CHECK) == NULL)
-+        {
-+          BUS_SET_OOM (error);
-+          return FALSE;
-+        }
-+
-       return TRUE;
-     }
-   else
-@@ -2284,6 +2329,7 @@ bus_config_parser_end_element (BusConfigParser   *parser,
-     case ELEMENT_POLICY:
-     case ELEMENT_ALLOW:
-     case ELEMENT_DENY:
-+    case ELEMENT_CHECK:
-     case ELEMENT_FORK:
-     case ELEMENT_SYSLOG:
-     case ELEMENT_KEEP_UMASK:
-@@ -2600,6 +2646,7 @@ bus_config_parser_content (BusConfigParser   *parser,
-     case ELEMENT_POLICY:
-     case ELEMENT_ALLOW:
-     case ELEMENT_DENY:
-+    case ELEMENT_CHECK:
-     case ELEMENT_FORK:
-     case ELEMENT_SYSLOG:
-     case ELEMENT_KEEP_UMASK:
-@@ -3127,6 +3174,8 @@ do_load (const DBusString *full_path,
-   dbus_error_init (&error);
-   parser = bus_config_load (full_path, TRUE, NULL, &error);
-+  if (dbus_error_is_set (&error))
-+    _dbus_verbose ("Failed to load file: %s\n", error.message);
-   if (parser == NULL)
-     {
-       _DBUS_ASSERT_ERROR_IS_SET (&error);
-@@ -3359,6 +3408,7 @@ elements_equal (const Element *a,
-     case ELEMENT_LISTEN:
-     case ELEMENT_AUTH:
-     case ELEMENT_ALLOW:
-+    case ELEMENT_CHECK:
-     case ELEMENT_DENY:
-     case ELEMENT_FORK:
-     case ELEMENT_PIDFILE:
-diff --git a/bus/connection.c b/bus/connection.c
-index 53605fa..b348d42 100644
---- a/bus/connection.c
-+++ b/bus/connection.c
-@@ -36,6 +36,10 @@
- #include <dbus/dbus-timeout.h>
- #include <dbus/dbus-connection-internal.h>
- #include <dbus/dbus-internals.h>
-+#ifdef DBUS_ENABLE_CYNARA
-+#include <stdlib.h>
-+#include <cynara-session.h>
-+#endif
- /* Trim executed commands to this length; we want to keep logs readable */
- #define MAX_LOG_COMMAND_LEN 50
-@@ -116,6 +120,9 @@ typedef struct
-   /** non-NULL if and only if this is a monitor */
-   DBusList *link_in_monitors;
-+#ifdef DBUS_ENABLE_CYNARA
-+  char *cynara_session_id;
-+#endif
- } BusConnectionData;
- static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
-@@ -129,8 +136,8 @@ static dbus_bool_t expire_incomplete_timeout (void *data);
- #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
--static DBusLoop*
--connection_get_loop (DBusConnection *connection)
-+DBusLoop*
-+bus_connection_get_loop (DBusConnection *connection)
- {
-   BusConnectionData *d;
-@@ -354,7 +361,7 @@ add_connection_watch (DBusWatch      *watch,
- {
-   DBusConnection *connection = data;
--  return _dbus_loop_add_watch (connection_get_loop (connection), watch);
-+  return _dbus_loop_add_watch (bus_connection_get_loop (connection), watch);
- }
- static void
-@@ -363,7 +370,7 @@ remove_connection_watch (DBusWatch      *watch,
- {
-   DBusConnection *connection = data;
-   
--  _dbus_loop_remove_watch (connection_get_loop (connection), watch);
-+  _dbus_loop_remove_watch (bus_connection_get_loop (connection), watch);
- }
- static void
-@@ -372,7 +379,7 @@ toggle_connection_watch (DBusWatch      *watch,
- {
-   DBusConnection *connection = data;
--  _dbus_loop_toggle_watch (connection_get_loop (connection), watch);
-+  _dbus_loop_toggle_watch (bus_connection_get_loop (connection), watch);
- }
- static dbus_bool_t
-@@ -381,7 +388,7 @@ add_connection_timeout (DBusTimeout    *timeout,
- {
-   DBusConnection *connection = data;
-   
--  return _dbus_loop_add_timeout (connection_get_loop (connection), timeout);
-+  return _dbus_loop_add_timeout (bus_connection_get_loop (connection), timeout);
- }
- static void
-@@ -390,7 +397,7 @@ remove_connection_timeout (DBusTimeout    *timeout,
- {
-   DBusConnection *connection = data;
-   
--  _dbus_loop_remove_timeout (connection_get_loop (connection), timeout);
-+  _dbus_loop_remove_timeout (bus_connection_get_loop (connection), timeout);
- }
- static void
-@@ -448,6 +455,10 @@ free_connection_data (void *data)
-   
-   dbus_free (d->name);
-   
-+#ifdef DBUS_ENABLE_CYNARA
-+  free (d->cynara_session_id);
-+#endif
-+
-   dbus_free (d);
- }
-@@ -1078,6 +1089,22 @@ bus_connection_get_policy (DBusConnection *connection)
-   return d->policy;
- }
-+#ifdef DBUS_ENABLE_CYNARA
-+const char *bus_connection_get_cynara_session_id (DBusConnection *connection)
-+{
-+  BusConnectionData *d = BUS_CONNECTION_DATA (connection);
-+  _dbus_assert (d != NULL);
-+
-+  if (d->cynara_session_id == NULL)
-+    {
-+      unsigned long pid;
-+      if (dbus_connection_get_unix_process_id(connection, &pid))
-+        d->cynara_session_id = cynara_session_from_pid(pid);
-+    }
-+  return d->cynara_session_id;
-+}
-+#endif
-+
- static dbus_bool_t
- foreach_active (BusConnections               *connections,
-                 BusConnectionForeachFunction  function,
-@@ -2333,6 +2360,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
-                                   DBusMessage    *message)
- {
-   DBusError error = DBUS_ERROR_INIT;
-+  BusResult res;
-   /* We have to set the sender to the driver, and have
-    * to check security policy since it was not done in
-@@ -2370,10 +2398,11 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
-    * if we're actively capturing messages, it's nice to log that we
-    * tried to send it and did not allow ourselves to do so.
-    */
--  if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
--                                          transaction,
--                                          NULL, connection, connection,
--                                          message, NULL, &error))
-+  res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
-+                                           transaction,
-+                                           NULL, connection, connection, message, NULL,
-+                                           &error, NULL);
-+  if (res == BUS_RESULT_FALSE)
-     {
-       if (!bus_transaction_capture_error_reply (transaction, connection,
-                                                 &error, message))
-@@ -2388,6 +2417,12 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
-       dbus_error_free (&error);
-       return TRUE;
-     }
-+  else if (res == BUS_RESULT_LATER)
-+    {
-+      _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
-+      dbus_error_free (&error);
-+      return TRUE;
-+    }
-   return bus_transaction_send (transaction, connection, message);
- }
-diff --git a/bus/connection.h b/bus/connection.h
-index 9e253ae..71078ea 100644
---- a/bus/connection.h
-+++ b/bus/connection.h
-@@ -31,6 +31,7 @@
- typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection, 
-                                                       void           *data);
-+DBusLoop*       bus_connection_get_loop           (DBusConnection *connection);
- BusConnections* bus_connections_new               (BusContext                   *context);
- BusConnections* bus_connections_ref               (BusConnections               *connections);
-@@ -124,6 +125,9 @@ dbus_bool_t bus_connection_be_monitor (DBusConnection  *connection,
-                                        BusTransaction  *transaction,
-                                        DBusList       **rules,
-                                        DBusError       *error);
-+#ifdef DBUS_ENABLE_CYNARA
-+const char *bus_connection_get_cynara_session_id (DBusConnection *connection);
-+#endif
- /* transaction API so we can send or not send a block of messages as a whole */
-diff --git a/bus/cynara.c b/bus/cynara.c
-new file mode 100644
-index 0000000..57a4c45
---- /dev/null
-+++ b/bus/cynara.c
-@@ -0,0 +1,374 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* cynara.c  Cynara runtime privilege checking
-+ *
-+ * Copyright (c) 2014 Samsung Electronics, Ltd.
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-+ *
-+ */
-+
-+#include <config.h>
-+#include "cynara.h"
-+#include "check.h"
-+#include "utils.h"
-+
-+#include <stdio.h>
-+
-+#include <dbus/dbus.h>
-+#include <dbus/dbus-watch.h>
-+#include <dbus/dbus-connection-internal.h>
-+#include <bus/connection.h>
-+#ifdef DBUS_ENABLE_CYNARA
-+#include <cynara-client-async.h>
-+#endif
-+
-+
-+#ifdef DBUS_ENABLE_CYNARA
-+typedef struct BusCynara
-+{
-+  int refcount;
-+
-+  BusContext   *context;
-+  BusCheck     *check;
-+  cynara_async *cynara;
-+  DBusWatch    *cynara_watch;
-+} BusCynara;
-+
-+#define USE_CYNARA_CACHE 1
-+#ifdef USE_CYNARA_CACHE
-+#define CYNARA_CACHE_SIZE 1000
-+#endif
-+
-+static dbus_bool_t bus_cynara_watch_callback(DBusWatch *watch,
-+                                             unsigned int flags,
-+                                             void *data);
-+
-+static void status_callback(int old_fd,
-+                            int new_fd,
-+                            cynara_async_status status,
-+                            void *user_status_data);
-+static void bus_cynara_check_response_callback (cynara_check_id check_id,
-+                                                cynara_async_call_cause cause,
-+                                                int response,
-+                                                void *user_response_data);
-+#endif
-+
-+
-+BusCynara *
-+bus_cynara_new(BusCheck *check, DBusError *error)
-+{
-+#ifdef DBUS_ENABLE_CYNARA
-+  BusContext *context;
-+  BusCynara *cynara;
-+  cynara_async_configuration *conf = NULL;
-+  int ret;
-+
-+  cynara = dbus_new(BusCynara, 1);
-+  if (cynara == NULL)
-+    {
-+      BUS_SET_OOM(error);
-+      return NULL;
-+    }
-+
-+  context = bus_check_get_context(check);
-+
-+  cynara->refcount = 1;
-+  cynara->check = check;
-+  cynara->context = context;
-+  cynara->cynara_watch = NULL;
-+
-+  ret = cynara_async_configuration_create(&conf);
-+  if (ret != CYNARA_API_SUCCESS)
-+    {
-+      dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to create Cynara configuration");
-+      goto out;
-+    }
-+
-+#ifdef CYNARA_CACHE_SIZE
-+  ret = cynara_async_configuration_set_cache_size(conf, CYNARA_CACHE_SIZE);
-+  if (ret != CYNARA_API_SUCCESS)
-+    {
-+      dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to Cynara cache size");
-+      goto out;
-+    }
-+#endif
-+
-+  ret = cynara_async_initialize(&cynara->cynara, conf, &status_callback, cynara);
-+  if (ret != CYNARA_API_SUCCESS)
-+    {
-+      dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to initialize Cynara client");
-+      goto out;
-+    }
-+
-+out:
-+  cynara_async_configuration_destroy(conf);
-+  if (ret != CYNARA_API_SUCCESS)
-+    {
-+      dbus_free(cynara);
-+      return NULL;
-+    }
-+
-+  return cynara;
-+#else
-+  return NULL;
-+#endif
-+}
-+
-+BusCynara *
-+bus_cynara_ref (BusCynara *cynara)
-+{
-+#ifdef DBUS_ENABLE_CYNARA
-+  _dbus_assert (cynara->refcount > 0);
-+  cynara->refcount += 1;
-+
-+  return cynara;
-+#else
-+  return NULL;
-+#endif
-+}
-+
-+void
-+bus_cynara_unref (BusCynara *cynara)
-+{
-+#ifdef DBUS_ENABLE_CYNARA
-+  _dbus_assert (cynara->refcount > 0);
-+
-+  cynara->refcount -= 1;
-+
-+  if (cynara->refcount == 0)
-+    {
-+      cynara_async_finish(cynara->cynara);
-+      dbus_free(cynara);
-+    }
-+#endif
-+}
-+
-+BusResult
-+bus_cynara_check_privilege (BusCynara *cynara,
-+                            DBusMessage *message,
-+                            DBusConnection *sender,
-+                            DBusConnection *addressed_recipient,
-+                            DBusConnection *proposed_recipient,
-+                            const char *privilege,
-+                            BusDeferredMessageStatus check_type,
-+                            BusDeferredMessage **deferred_message_param)
-+{
-+#ifdef DBUS_ENABLE_CYNARA
-+  int result;
-+  unsigned long uid;
-+  char *label;
-+  const char *session_id;
-+  char user[32];
-+  cynara_check_id check_id;
-+  DBusConnection *connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
-+  BusDeferredMessage *deferred_message;
-+  BusResult ret;
-+
-+  _dbus_assert(connection != NULL);
-+
-+  if (dbus_connection_get_unix_user(connection, &uid) == FALSE)
-+      return BUS_RESULT_FALSE;
-+
-+  if (_dbus_connection_get_linux_security_label(connection, &label) == FALSE || label == NULL)
-+    {
-+      _dbus_warn("Failed to obtain security label for connection\n");
-+      return BUS_RESULT_FALSE;
-+    }
-+
-+  session_id = bus_connection_get_cynara_session_id (connection);
-+  if (session_id == NULL)
-+    {
-+      ret = BUS_RESULT_FALSE;
-+      goto out;
-+    }
-+
-+  snprintf(user, sizeof(user), "%lu", uid);
-+
-+#if USE_CYNARA_CACHE
-+  result = cynara_async_check_cache(cynara->cynara, label, session_id, user, privilege);
-+#else
-+  result = CYNARA_API_CACHE_MISS;
-+#endif
-+
-+  switch (result)
-+  {
-+  case CYNARA_API_ACCESS_ALLOWED:
-+    _dbus_verbose("Cynara: got ALLOWED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
-+               label, session_id, user, privilege);
-+    ret = BUS_RESULT_TRUE;
-+    break;
-+
-+  case CYNARA_API_ACCESS_DENIED:
-+    _dbus_verbose("Cynara: got DENIED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
-+               label, session_id, user, privilege);
-+    ret = BUS_RESULT_FALSE;
-+    break;
-+
-+  case CYNARA_API_CACHE_MISS:
-+     deferred_message = bus_deferred_message_new(message, sender, addressed_recipient,
-+         proposed_recipient, BUS_RESULT_LATER);
-+     if (deferred_message == NULL)
-+       {
-+         _dbus_verbose("Failed to allocate memory for deferred message\n");
-+         ret = BUS_RESULT_FALSE;
-+         goto out;
-+       }
-+
-+    /* callback is supposed to unref deferred_message*/
-+    result = cynara_async_create_request(cynara->cynara, label, session_id, user, privilege, &check_id,
-+        &bus_cynara_check_response_callback, deferred_message);
-+    if (result == CYNARA_API_SUCCESS)
-+      {
-+        _dbus_verbose("Created Cynara request: client=%s session_id=%s user=%s privilege=%s check_id=%u "
-+            "deferred_message=%p\n", label, session_id, user, privilege, (unsigned int)check_id, deferred_message);
-+        if (deferred_message_param != NULL)
-+          *deferred_message_param = deferred_message;
-+        ret = BUS_RESULT_LATER;
-+      }
-+    else
-+      {
-+        _dbus_verbose("Error on cynara request create: %i\n", result);
-+        bus_deferred_message_unref(deferred_message);
-+        ret = BUS_RESULT_FALSE;
-+      }
-+    break;
-+  default:
-+    _dbus_verbose("Error when accessing Cynara cache: %i\n", result);
-+    ret = BUS_RESULT_FALSE;
-+  }
-+out:
-+  dbus_free(label);
-+  return ret;
-+
-+#else
-+  return BUS_RESULT_FALSE;
-+#endif
-+}
-+
-+
-+
-+#ifdef DBUS_ENABLE_CYNARA
-+static void
-+status_callback(int old_fd, int new_fd, cynara_async_status status,
-+                void *user_status_data)
-+{
-+  BusCynara *cynara = (BusCynara *)user_status_data;
-+  DBusLoop *loop = bus_context_get_loop(cynara->context);
-+
-+  if (cynara->cynara_watch != NULL)
-+    {
-+      _dbus_loop_remove_watch(loop, cynara->cynara_watch);
-+      _dbus_watch_invalidate(cynara->cynara_watch);
-+      _dbus_watch_unref(cynara->cynara_watch);
-+      cynara->cynara_watch = NULL;
-+    }
-+
-+  if (new_fd != -1)
-+    {
-+      unsigned int flags;
-+      DBusWatch *watch;
-+
-+      switch (status)
-+      {
-+      case CYNARA_STATUS_FOR_READ:
-+        flags = DBUS_WATCH_READABLE;
-+        break;
-+      case CYNARA_STATUS_FOR_RW:
-+        flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
-+        break;
-+      default:
-+        /* Cynara passed unknown status - warn and add RW watch */
-+        _dbus_verbose("Cynara passed unknown status value: 0x%08X\n", (unsigned int)status);
-+        flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
-+        break;
-+      }
-+
-+      watch = _dbus_watch_new(new_fd, flags, TRUE, &bus_cynara_watch_callback, cynara, NULL);
-+      if (watch != NULL)
-+        {
-+          if (_dbus_loop_add_watch(loop, watch) == TRUE)
-+            {
-+              cynara->cynara_watch = watch;
-+              return;
-+            }
-+
-+          _dbus_watch_invalidate(watch);
-+          _dbus_watch_unref(watch);
-+        }
-+
-+      /* It seems like not much can be done at this point. Cynara events won't be processed
-+       * until next Cynara function call triggering status callback */
-+      _dbus_verbose("Failed to add dbus watch\n");
-+    }
-+}
-+
-+static dbus_bool_t
-+bus_cynara_watch_callback(DBusWatch    *watch,
-+                          unsigned int  flags,
-+                          void         *data)
-+{
-+  BusCynara *cynara = (BusCynara *)data;
-+  int result = cynara_async_process(cynara->cynara);
-+  if (result != CYNARA_API_SUCCESS)
-+      _dbus_verbose("cynara_async_process returned %d\n", result);
-+
-+  return result != CYNARA_API_OUT_OF_MEMORY ? TRUE : FALSE;
-+}
-+
-+static inline const char *
-+call_cause_to_string(cynara_async_call_cause cause)
-+{
-+  switch (cause)
-+  {
-+  case CYNARA_CALL_CAUSE_ANSWER:
-+    return "ANSWER";
-+  case CYNARA_CALL_CAUSE_CANCEL:
-+    return "CANCEL";
-+  case CYNARA_CALL_CAUSE_FINISH:
-+    return "FINSIH";
-+  case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE:
-+    return "SERVICE NOT AVAILABLE";
-+  default:
-+    return "INVALID";
-+  }
-+}
-+
-+static void
-+bus_cynara_check_response_callback (cynara_check_id check_id,
-+                                    cynara_async_call_cause cause,
-+                                    int response,
-+                                    void *user_response_data)
-+{
-+  BusDeferredMessage *deferred_message = user_response_data;
-+  BusResult result;
-+
-+  _dbus_verbose("Cynara callback: check_id=%u, cause=%s response=%i response_data=%p\n",
-+      (unsigned int)check_id, call_cause_to_string(cause), response, user_response_data);
-+
-+  if (deferred_message == NULL)
-+    return;
-+
-+  if (cause == CYNARA_CALL_CAUSE_ANSWER && response == CYNARA_API_ACCESS_ALLOWED)
-+    result = BUS_RESULT_TRUE;
-+  else
-+    result = BUS_RESULT_FALSE;
-+
-+  bus_deferred_message_response_received(deferred_message, result);
-+  bus_deferred_message_unref(deferred_message);
-+}
-+
-+#endif /* DBUS_ENABLE_CYNARA */
-diff --git a/bus/cynara.h b/bus/cynara.h
-new file mode 100644
-index 0000000..c4728bb
---- /dev/null
-+++ b/bus/cynara.h
-@@ -0,0 +1,37 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* cynara.h  Cynara runtime privilege checking
-+ *
-+ * Copyright (c) 2014 Samsung Electronics, Ltd.
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-+ *
-+ */
-+
-+#include "bus.h"
-+#include "check.h"
-+
-+BusCynara *bus_cynara_new             (BusCheck *check, DBusError *error);
-+BusCynara *bus_cynara_ref             (BusCynara *cynara);
-+void       bus_cynara_unref           (BusCynara *cynara);
-+BusResult  bus_cynara_check_privilege (BusCynara *cynara,
-+                                       DBusMessage *message,
-+                                       DBusConnection *sender,
-+                                       DBusConnection *addressed_recipient,
-+                                       DBusConnection *proposed_recipient,
-+                                       const char *privilege,
-+                                       BusDeferredMessageStatus check_type,
-+                                       BusDeferredMessage **deferred_message);
-diff --git a/bus/dispatch.c b/bus/dispatch.c
-index 19228be..d3867f7 100644
---- a/bus/dispatch.c
-+++ b/bus/dispatch.c
-@@ -25,6 +25,7 @@
- #include <config.h>
- #include "dispatch.h"
-+#include "check.h"
- #include "connection.h"
- #include "driver.h"
- #include "services.h"
-@@ -64,14 +65,18 @@ send_one_message (DBusConnection *connection,
-                   DBusError      *error)
- {
-   DBusError stack_error = DBUS_ERROR_INIT;
-+  BusDeferredMessage *deferred_message;
-+  BusResult result;
--  if (!bus_context_check_security_policy (context, transaction,
-+  result = bus_context_check_security_policy (context, transaction,
-                                           sender,
-                                           addressed_recipient,
-                                           connection,
-                                           message,
-                                           NULL,
--                                          &stack_error))
-+                                          &stack_error,
-+                                          &deferred_message);
-+  if (result != BUS_RESULT_TRUE)
-     {
-       if (!bus_transaction_capture_error_reply (transaction, sender,
-                                                 &stack_error, message))
-@@ -130,6 +135,8 @@ bus_dispatch_matches (BusTransaction *transaction,
-   BusMatchmaker *matchmaker;
-   DBusList *link;
-   BusContext *context;
-+  BusDeferredMessage *deferred_message;
-+  BusResult res;
-   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-@@ -145,11 +152,20 @@ bus_dispatch_matches (BusTransaction *transaction,
-   /* First, send the message to the addressed_recipient, if there is one. */
-   if (addressed_recipient != NULL)
-     {
--      if (!bus_context_check_security_policy (context, transaction,
--                                              sender, addressed_recipient,
--                                              addressed_recipient,
--                                              message, NULL, error))
-+      res = bus_context_check_security_policy (context, transaction,
-+                                               sender, addressed_recipient,
-+                                               addressed_recipient,
-+                                               message, NULL, error,
-+                                               &deferred_message);
-+      if (res == BUS_RESULT_FALSE)
-         return 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;
-+        }
-       if (dbus_message_contains_unix_fds (message) &&
-           !dbus_connection_can_send_type (addressed_recipient,
-@@ -374,19 +390,31 @@ bus_dispatch (DBusConnection *connection,
-   if (service_name &&
-       strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
-     {
-+      BusDeferredMessage *deferred_message;
-+      BusResult res;
-+
-       if (!bus_transaction_capture (transaction, connection, NULL, message))
-         {
-           BUS_SET_OOM (&error);
-           goto out;
-         }
--      if (!bus_context_check_security_policy (context, transaction,
--                                              connection, NULL, NULL, message,
--                                              NULL, &error))
-+      res = bus_context_check_security_policy (context, transaction,
-+                                               connection, NULL, NULL, message, NULL,
-+                                               &error, &deferred_message);
-+      if (res == BUS_RESULT_FALSE)
-         {
-           _dbus_verbose ("Security policy rejected message\n");
-           goto out;
-         }
-+      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");
-+          goto out;
-+        }
-       _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS);
-       if (!bus_driver_handle_message (connection, transaction, message, &error))
-diff --git a/bus/driver.h b/bus/driver.h
-index ac1289d..a7297ad 100644
---- a/bus/driver.h
-+++ b/bus/driver.h
-@@ -66,5 +66,7 @@ dbus_bool_t bus_driver_send_ack_reply     (DBusConnection  *connection,
-                                            BusTransaction  *transaction,
-                                            DBusMessage     *message,
-                                            DBusError       *error);
-+dbus_bool_t bus_driver_check_message_is_for_us (DBusMessage *message,
-+                                                DBusError   *error);
- #endif /* BUS_DRIVER_H */
-diff --git a/bus/policy.c b/bus/policy.c
-index a37be80..7de92c6 100644
---- a/bus/policy.c
-+++ b/bus/policy.c
-@@ -22,6 +22,7 @@
-  */
- #include <config.h>
-+#include "check.h"
- #include "policy.h"
- #include "services.h"
- #include "test.h"
-@@ -33,7 +34,7 @@
- BusPolicyRule*
- bus_policy_rule_new (BusPolicyRuleType type,
--                     dbus_bool_t       allow)
-+                     BusPolicyRuleAccess access)
- {
-   BusPolicyRule *rule;
-@@ -43,7 +44,7 @@ bus_policy_rule_new (BusPolicyRuleType type,
-   rule->type = type;
-   rule->refcount = 1;
--  rule->allow = allow;
-+  rule->access = access;
-   switch (rule->type)
-     {
-@@ -55,18 +56,19 @@ bus_policy_rule_new (BusPolicyRuleType type,
-       break;
-     case BUS_POLICY_RULE_SEND:
-       rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
--
-       /* allow rules default to TRUE (only requested replies allowed)
-+       * check rules default to TRUE (only requested replies are checked)
-        * deny rules default to FALSE (only unrequested replies denied)
-        */
--      rule->d.send.requested_reply = rule->allow;
-+      rule->d.send.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
-       break;
-     case BUS_POLICY_RULE_RECEIVE:
-       rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
-       /* allow rules default to TRUE (only requested replies allowed)
-+       * check rules default to TRUE (only requested replies are checked)
-        * deny rules default to FALSE (only unrequested replies denied)
-        */
--      rule->d.receive.requested_reply = rule->allow;
-+      rule->d.receive.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
-       break;
-     case BUS_POLICY_RULE_OWN:
-       break;
-@@ -122,7 +124,8 @@ bus_policy_rule_unref (BusPolicyRule *rule)
-         default:
-           _dbus_assert_not_reached ("invalid rule");
-         }
--      
-+
-+      dbus_free (rule->privilege);
-       dbus_free (rule);
-     }
- }
-@@ -435,7 +438,10 @@ list_allows_user (dbus_bool_t           def,
-       else
-         continue;
--      allowed = rule->allow;
-+      /* We don't intend to support <check user="..." /> and <check group="..." />
-+         rules. They are treated like deny.
-+      */
-+      allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
-     }
-   
-   return allowed;
-@@ -873,18 +879,23 @@ bus_client_policy_append_rule (BusClientPolicy *policy,
-   return TRUE;
- }
--dbus_bool_t
--bus_client_policy_check_can_send (BusClientPolicy *policy,
--                                  BusRegistry     *registry,
--                                  dbus_bool_t      requested_reply,
--                                  DBusConnection  *receiver,
--                                  DBusMessage     *message,
--                                  dbus_int32_t    *toggles,
--                                  dbus_bool_t     *log)
-+BusResult
-+bus_client_policy_check_can_send (DBusConnection      *sender,
-+                                  BusClientPolicy     *policy,
-+                                  BusRegistry         *registry,
-+                                  dbus_bool_t          requested_reply,
-+                                  DBusConnection      *addressed_recipient,
-+                                  DBusConnection      *receiver,
-+                                  DBusMessage         *message,
-+                                  dbus_int32_t        *toggles,
-+                                  dbus_bool_t         *log,
-+                                  const char         **privilege_param,
-+                                  BusDeferredMessage **deferred_message)
- {
-   DBusList *link;
--  dbus_bool_t allowed;
--  
-+  BusResult result;
-+  const char *privilege;
-+
-   /* policy->rules is in the order the rules appeared
-    * in the config file, i.e. last rule that applies wins
-    */
-@@ -892,7 +903,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
-   _dbus_verbose ("  (policy) checking send rules\n");
-   *toggles = 0;
-   
--  allowed = FALSE;
-+  result = BUS_RESULT_FALSE;
-   link = _dbus_list_get_first_link (&policy->rules);
-   while (link != NULL)
-     {
-@@ -923,13 +934,14 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
-       /* If it's a reply, the requested_reply flag kicks in */
-       if (dbus_message_get_reply_serial (message) != 0)
-         {
--          /* for allow, requested_reply=true means the rule applies
--           * only when reply was requested. requested_reply=false means
--           * always allow.
-+          /* for allow or check requested_reply=true means the rule applies
-+           * only when reply was requested. requested_reply=false means the
-+           * rule always applies
-            */
--          if (!requested_reply && rule->allow && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
-+          if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
-             {
--              _dbus_verbose ("  (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
-+              _dbus_verbose ("  (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
-+                  rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
-               continue;
-             }
-@@ -937,7 +949,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
-            * when the reply was not requested. requested_reply=true means the
-            * rule always applies.
-            */
--          if (requested_reply && !rule->allow && !rule->d.send.requested_reply)
-+          if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.send.requested_reply)
-             {
-               _dbus_verbose ("  (policy) skipping deny rule since it only applies to unrequested replies\n");
-               continue;
-@@ -960,13 +972,15 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
-           /* The interface is optional in messages. For allow rules, if the message
-            * has no interface we want to skip the rule (and thus not allow);
-            * for deny rules, if the message has no interface we want to use the
--           * rule (and thus deny).
-+           * rule (and thus deny). Check rules are meant to be used like allow
-+           * rules (they can grant access, but not remove it), so we treat it like
-+           * allow here.
-            */
-           dbus_bool_t no_interface;
-           no_interface = dbus_message_get_interface (message) == NULL;
-           
--          if ((no_interface && rule->allow) ||
-+          if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
-               (!no_interface && 
-                strcmp (dbus_message_get_interface (message),
-                        rule->d.send.interface) != 0))
-@@ -1079,33 +1093,64 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
-         }
-       /* Use this rule */
--      allowed = rule->allow;
-+      switch (rule->access)
-+        {
-+        case BUS_POLICY_RULE_ACCESS_ALLOW:
-+          result = BUS_RESULT_TRUE;
-+          break;
-+        case BUS_POLICY_RULE_ACCESS_DENY:
-+        default:
-+          result = BUS_RESULT_FALSE;
-+          break;
-+        case BUS_POLICY_RULE_ACCESS_CHECK:
-+          result = BUS_RESULT_LATER;
-+          privilege = rule->privilege;
-+          break;
-+        }
-+
-       *log = rule->d.send.log;
-       (*toggles)++;
--      _dbus_verbose ("  (policy) used rule, allow now = %d\n",
--                     allowed);
-+      _dbus_verbose ("  (policy) used rule, result now = %d\n",
-+                     (int)(intptr_t)result);
-     }
--  return allowed;
-+  if (result == BUS_RESULT_LATER)
-+    {
-+      BusContext *context = bus_connection_get_context(sender);
-+      BusCheck *check = bus_context_get_check(context);
-+
-+      result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
-+          privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
-+    }
-+  else
-+    privilege = NULL;
-+
-+  if (privilege_param != NULL)
-+    *privilege_param = privilege;
-+
-+  return result;
- }
- /* See docs on what the args mean on bus_context_check_security_policy()
-  * comment
-  */
--dbus_bool_t
--bus_client_policy_check_can_receive (BusClientPolicy *policy,
--                                     BusRegistry     *registry,
--                                     dbus_bool_t      requested_reply,
--                                     DBusConnection  *sender,
--                                     DBusConnection  *addressed_recipient,
--                                     DBusConnection  *proposed_recipient,
--                                     DBusMessage     *message,
--                                     dbus_int32_t    *toggles)
-+BusResult
-+bus_client_policy_check_can_receive (BusClientPolicy     *policy,
-+                                     BusRegistry         *registry,
-+                                     dbus_bool_t          requested_reply,
-+                                     DBusConnection      *sender,
-+                                     DBusConnection      *addressed_recipient,
-+                                     DBusConnection      *proposed_recipient,
-+                                     DBusMessage         *message,
-+                                     dbus_int32_t        *toggles,
-+                                     const char         **privilege_param,
-+                                     BusDeferredMessage **deferred_message)
- {
-   DBusList *link;
--  dbus_bool_t allowed;
-   dbus_bool_t eavesdropping;
-+  BusResult result;
-+  const char *privilege;
-   eavesdropping =
-     addressed_recipient != proposed_recipient &&
-@@ -1118,7 +1163,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
-   _dbus_verbose ("  (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
-   *toggles = 0;
-   
--  allowed = FALSE;
-+  result = BUS_RESULT_FALSE;
-   link = _dbus_list_get_first_link (&policy->rules);
-   while (link != NULL)
-     {
-@@ -1141,19 +1186,21 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
-             }
-         }
--      /* for allow, eavesdrop=false means the rule doesn't apply when
--       * eavesdropping. eavesdrop=true means always allow.
-+
-+      /* for allow or check, eavesdrop=false means the rule doesn't apply when
-+       * eavesdropping. eavesdrop=true means the rule always applies
-        */
--      if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop)
-+      if (eavesdropping && rule->access != BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.eavesdrop)
-         {
--          _dbus_verbose ("  (policy) skipping allow rule since it doesn't apply to eavesdropping\n");
-+          _dbus_verbose ("  (policy) skipping %s rule since it doesn't apply to eavesdropping\n",
-+              rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
-           continue;
-         }
-       /* for deny, eavesdrop=true means the rule applies only when
-        * eavesdropping; eavesdrop=false means always deny.
-        */
--      if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop)
-+      if (!eavesdropping && rule->access == BUS_POLICY_RULE_ACCESS_DENY && rule->d.receive.eavesdrop)
-         {
-           _dbus_verbose ("  (policy) skipping deny rule since it only applies to eavesdropping\n");
-           continue;
-@@ -1162,13 +1209,14 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
-       /* If it's a reply, the requested_reply flag kicks in */
-       if (dbus_message_get_reply_serial (message) != 0)
-         {
--          /* for allow, requested_reply=true means the rule applies
--           * only when reply was requested. requested_reply=false means
--           * always allow.
-+          /* for allow or check requested_reply=true means the rule applies
-+           * only when reply was requested. requested_reply=false means the
-+           * rule always applies
-            */
--          if (!requested_reply && rule->allow && rule->d.receive.requested_reply && !rule->d.receive.eavesdrop)
-+          if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
-             {
--              _dbus_verbose ("  (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
-+              _dbus_verbose ("  (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
-+                  rule->access == BUS_POLICY_RULE_ACCESS_DENY ? "allow" : "deny");
-               continue;
-             }
-@@ -1176,7 +1224,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
-            * when the reply was not requested. requested_reply=true means the
-            * rule always applies.
-            */
--          if (requested_reply && !rule->allow && !rule->d.receive.requested_reply)
-+          if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.requested_reply)
-             {
-               _dbus_verbose ("  (policy) skipping deny rule since it only applies to unrequested replies\n");
-               continue;
-@@ -1199,13 +1247,13 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
-           /* The interface is optional in messages. For allow rules, if the message
-            * has no interface we want to skip the rule (and thus not allow);
-            * for deny rules, if the message has no interface we want to use the
--           * rule (and thus deny).
-+           * rule (and thus deny). Check rules are treated like allow rules.
-            */
-           dbus_bool_t no_interface;
-           no_interface = dbus_message_get_interface (message) == NULL;
-           
--          if ((no_interface && rule->allow) ||
-+          if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
-               (!no_interface &&
-                strcmp (dbus_message_get_interface (message),
-                        rule->d.receive.interface) != 0))
-@@ -1295,14 +1343,43 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
-         }
-       /* Use this rule */
--      allowed = rule->allow;
-+      switch (rule->access)
-+      {
-+        case BUS_POLICY_RULE_ACCESS_ALLOW:
-+          result = BUS_RESULT_TRUE;
-+          break;
-+        case BUS_POLICY_RULE_ACCESS_DENY:
-+        default:
-+          result = BUS_RESULT_FALSE;
-+          break;
-+        case BUS_POLICY_RULE_ACCESS_CHECK:
-+          result = BUS_RESULT_LATER;
-+          privilege = rule->privilege;
-+          break;
-+      }
-+
-       (*toggles)++;
--      _dbus_verbose ("  (policy) used rule, allow now = %d\n",
--                     allowed);
-+      _dbus_verbose ("  (policy) used rule, result now = %d\n",
-+                     (int)(intptr_t)result);
-     }
--  return allowed;
-+
-+  if (result == BUS_RESULT_LATER)
-+    {
-+      BusContext *context = bus_connection_get_context(proposed_recipient);
-+      BusCheck *check = bus_context_get_check(context);
-+
-+      result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
-+                 privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
-+    }
-+  else
-+      privilege = NULL;
-+
-+  if (privilege_param != NULL)
-+     *privilege_param = privilege;
-+
-+  return result;
- }
-@@ -1354,7 +1431,7 @@ bus_rules_check_can_own (DBusList *rules,
-         }
-       /* Use this rule */
--      allowed = rule->allow;
-+      allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
-     }
-   return allowed;
-diff --git a/bus/policy.h b/bus/policy.h
-index ec43ffa..f839d23 100644
---- a/bus/policy.h
-+++ b/bus/policy.h
-@@ -46,6 +46,14 @@ typedef enum
-   BUS_POLICY_TRISTATE_TRUE
- } BusPolicyTristate;
-+typedef enum
-+{
-+  BUS_POLICY_RULE_ACCESS_DENY,
-+  BUS_POLICY_RULE_ACCESS_ALLOW,
-+  /** runtime check resulting in allow or deny */
-+  BUS_POLICY_RULE_ACCESS_CHECK
-+} BusPolicyRuleAccess;
-+
- /** determines whether the rule affects a connection, or some global item */
- #define BUS_POLICY_RULE_IS_PER_CLIENT(rule) (!((rule)->type == BUS_POLICY_RULE_USER || \
-                                                (rule)->type == BUS_POLICY_RULE_GROUP))
-@@ -56,8 +64,9 @@ struct BusPolicyRule
-   
-   BusPolicyRuleType type;
--  unsigned int allow : 1; /**< #TRUE if this allows, #FALSE if it denies */
--  
-+  unsigned int access : 2; /**< BusPolicyRuleAccess */
-+  char *privilege; /**< for BUS_POLICY_RULE_ACCESS_CHECK */
-+
-   union
-   {
-     struct
-@@ -118,7 +127,7 @@ struct BusPolicyRule
- };
- BusPolicyRule* bus_policy_rule_new   (BusPolicyRuleType type,
--                                      dbus_bool_t       allow);
-+                                      BusPolicyRuleAccess access);
- BusPolicyRule* bus_policy_rule_ref   (BusPolicyRule    *rule);
- void           bus_policy_rule_unref (BusPolicyRule    *rule);
-@@ -152,21 +161,27 @@ dbus_bool_t      bus_policy_merge                 (BusPolicy        *policy,
- BusClientPolicy* bus_client_policy_new               (void);
- BusClientPolicy* bus_client_policy_ref               (BusClientPolicy  *policy);
- void             bus_client_policy_unref             (BusClientPolicy  *policy);
--dbus_bool_t      bus_client_policy_check_can_send    (BusClientPolicy  *policy,
-+BusResult        bus_client_policy_check_can_send    (DBusConnection   *sender,
-+                                                      BusClientPolicy  *policy,
-                                                       BusRegistry      *registry,
-                                                       dbus_bool_t       requested_reply,
-+                                                      DBusConnection   *addressed_recipient,
-                                                       DBusConnection   *receiver,
-                                                       DBusMessage      *message,
-                                                       dbus_int32_t     *toggles,
--                                                      dbus_bool_t      *log);
--dbus_bool_t      bus_client_policy_check_can_receive (BusClientPolicy  *policy,
-+                                                      dbus_bool_t      *log,
-+                                                      const char      **privilege_param,
-+                                                      BusDeferredMessage **deferred_message);
-+BusResult        bus_client_policy_check_can_receive (BusClientPolicy  *policy,
-                                                       BusRegistry      *registry,
-                                                       dbus_bool_t       requested_reply,
-                                                       DBusConnection   *sender,
-                                                       DBusConnection   *addressed_recipient,
-                                                       DBusConnection   *proposed_recipient,
-                                                       DBusMessage      *message,
--                                                      dbus_int32_t     *toggles);
-+                                                      dbus_int32_t     *toggles,
-+                                                      const char      **privilege_param,
-+                                                      BusDeferredMessage **deferred_message);
- dbus_bool_t      bus_client_policy_check_can_own     (BusClientPolicy  *policy,
-                                                       const DBusString *service_name);
- dbus_bool_t      bus_client_policy_append_rule       (BusClientPolicy  *policy,
-diff --git a/configure.ac b/configure.ac
-index d1e3a29..11b5ffd 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1742,6 +1742,17 @@ AC_ARG_ENABLE([user-session],
- AM_CONDITIONAL([DBUS_ENABLE_USER_SESSION],
-   [test "x$enable_user_session" = xyes])
-+#enable cynara integration
-+AC_ARG_ENABLE([cynara], [AS_HELP_STRING([--enable-cynara], [enable Cynara integration])], [], [enable_cynara=no])
-+if test "x$enable_cynara" = xyes; then
-+  PKG_CHECK_MODULES([CYNARA], [cynara-client-async >= 0.6.0 cynara-session >= 0.6.0],
-+     [AC_DEFINE([DBUS_ENABLE_CYNARA], [1], [Define to enable Cynara privilege checks in dbus-daemon])],
-+     [AC_MSG_ERROR([libcynara-client-async and cynara-session are required to enable Cynara integration])])
-+fi
-+
-+AC_SUBST([CYNARA_CFLAGS])
-+AC_SUBST([CYNARA_LIBS])
-+
- AC_CONFIG_FILES([
- Doxyfile
- dbus/Version
-@@ -1824,6 +1835,7 @@ echo "
-         Building bus stats API:   ${enable_stats}
-         Building SELinux support: ${have_selinux}
-         Building AppArmor support: ${have_apparmor}
-+        Building Cynara support:  ${enable_cynara}
-         Building inotify support: ${have_inotify}
-         Building kqueue support:  ${have_kqueue}
-         Building systemd support: ${have_systemd}
-diff --git a/test/Makefile.am b/test/Makefile.am
-index af1e13b..e6f50e1 100644
---- a/test/Makefile.am
-+++ b/test/Makefile.am
-@@ -439,6 +439,7 @@ in_data = \
-       data/valid-config-files/debug-allow-all.conf.in \
-       data/valid-config-files/finite-timeout.conf.in \
-       data/valid-config-files/forbidding.conf.in \
-+      data/valid-config-files/debug-check-some.conf.in \
-       data/valid-config-files/incoming-limit.conf.in \
-       data/valid-config-files/max-completed-connections.conf.in \
-       data/valid-config-files/max-connections-per-user.conf.in \
-diff --git a/test/data/invalid-config-files/badcheck-1.conf b/test/data/invalid-config-files/badcheck-1.conf
-new file mode 100644
-index 0000000..fad9f50
---- /dev/null
-+++ b/test/data/invalid-config-files/badcheck-1.conf
-@@ -0,0 +1,9 @@
-+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
-+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-+<busconfig>
-+  <user>mybususer</user>
-+  <listen>unix:path=/foo/bar</listen>
-+  <policy context="default">
-+    <allow privilege="foo" send_destination="*"/> <!-- extra privilege="foo" -->
-+  </policy>
-+</busconfig>
-diff --git a/test/data/invalid-config-files/badcheck-2.conf b/test/data/invalid-config-files/badcheck-2.conf
-new file mode 100644
-index 0000000..63c7ef2
---- /dev/null
-+++ b/test/data/invalid-config-files/badcheck-2.conf
-@@ -0,0 +1,9 @@
-+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
-+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-+<busconfig>
-+  <user>mybususer</user>
-+  <listen>unix:path=/foo/bar</listen>
-+  <policy context="default">
-+    <check send_destination="*"/> <!-- missing privilege="foo" -->
-+  </policy>
-+</busconfig>
-diff --git a/test/data/valid-config-files/check-1.conf b/test/data/valid-config-files/check-1.conf
-new file mode 100644
-index 0000000..ad71473
---- /dev/null
-+++ b/test/data/valid-config-files/check-1.conf
-@@ -0,0 +1,9 @@
-+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
-+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-+<busconfig>
-+  <user>mybususer</user>
-+  <listen>unix:path=/foo/bar</listen>
-+  <policy context="default">
-+    <check privilege="foo" send_destination="*"/>
-+  </policy>
-+</busconfig>
-diff --git a/test/data/valid-config-files/debug-check-some.conf.in b/test/data/valid-config-files/debug-check-some.conf.in
-new file mode 100644
-index 0000000..47ee854
---- /dev/null
-+++ b/test/data/valid-config-files/debug-check-some.conf.in
-@@ -0,0 +1,18 @@
-+<!-- Bus that listens on a debug pipe and doesn't create any restrictions -->
-+
-+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
-+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-+<busconfig>
-+  <listen>debug-pipe:name=test-server</listen>
-+  <listen>@TEST_LISTEN@</listen>
-+  <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
-+  <policy context="default">
-+    <allow send_interface="*"/>
-+    <allow receive_interface="*"/>
-+    <allow own="*"/>
-+    <allow user="*"/>
-+
-+    <deny send_interface="org.freedesktop.TestSuite" send_member="Echo"/>
-+    <check privilege="foo" send_interface="org.freedesktop.TestSuite" send_member="Echo"/>
-+  </policy>
-+</busconfig>
--- 
-2.21.1
-