dbus-cynara: Upgrade to 1.10.20
[AGL/meta-agl.git] / meta-security / recipes-core / dbus-cynara / dbus / 0001-Integration-of-Cynara-asynchronous-security-checks.patch
diff --git a/meta-security/recipes-core/dbus-cynara/dbus/0001-Integration-of-Cynara-asynchronous-security-checks.patch b/meta-security/recipes-core/dbus-cynara/dbus/0001-Integration-of-Cynara-asynchronous-security-checks.patch
new file mode 100644 (file)
index 0000000..6a7e8a3
--- /dev/null
@@ -0,0 +1,2261 @@
+From 8f69153081140fa4c347ab1729c348ec77b309ec 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/5] 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.
+
+Change-Id: I9bcbce34577e5dc2a3cecf6233a0a2b0e43e1108
+Signed-off-by: José Bollo <jose.bollo@iot.bzh>
+---
+ bus/Makefile.am                                    |   6 +
+ bus/bus.c                                          | 136 +++++---
+ bus/bus.h                                          |  32 +-
+ bus/check.c                                        | 217 ++++++++++++
+ bus/check.h                                        |  68 ++++
+ bus/config-parser-common.c                         |   6 +
+ bus/config-parser-common.h                         |   1 +
+ bus/config-parser.c                                |  71 +++-
+ bus/connection.c                                   |  56 ++-
+ bus/connection.h                                   |   4 +
+ bus/cynara.c                                       | 374 +++++++++++++++++++++
+ bus/cynara.h                                       |  37 ++
+ bus/dispatch.c                                     |  44 ++-
+ bus/policy.c                                       | 193 +++++++----
+ bus/policy.h                                       |  51 ++-
+ configure.ac                                       |  12 +
+ test/Makefile.am                                   |   1 +
+ test/data/invalid-config-files/badcheck-1.conf     |   9 +
+ test/data/invalid-config-files/badcheck-2.conf     |   9 +
+ test/data/valid-config-files/check-1.conf          |   9 +
+ .../valid-config-files/debug-check-some.conf.in    |  18 +
+ tools/dbus-send.c                                  |   2 +-
+ 22 files changed, 1193 insertions(+), 163 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 33af09b0..3f57cc48 100644
+--- a/bus/Makefile.am
++++ b/bus/Makefile.am
+@@ -9,6 +9,7 @@ DBUS_BUS_LIBS = \
+       $(THREAD_LIBS) \
+       $(ADT_LIBS) \
+       $(NETWORK_libs) \
++      $(CYNARA_LIBS) \
+       $(NULL)
+ DBUS_LAUNCHER_LIBS = \
+@@ -24,6 +25,7 @@ AM_CPPFLAGS = \
+       $(APPARMOR_CFLAGS) \
+       -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \
+       -DDBUS_COMPILATION \
++      $(CYNARA_CFLAGS) \
+       $(NULL)
+ # if assertions are enabled, improve backtraces
+@@ -82,12 +84,16 @@ BUS_SOURCES=                                       \
+       audit.h                                 \
+       bus.c                                   \
+       bus.h                                   \
++      check.c                                 \
++      check.h                                 \
+       config-parser.c                         \
+       config-parser.h                         \
+       config-parser-common.c                  \
+       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/bus.c b/bus/bus.c
+index fd4ab9e4..c4008505 100644
+--- a/bus/bus.c
++++ b/bus/bus.c
+@@ -37,6 +37,7 @@
+ #include "apparmor.h"
+ #include "audit.h"
+ #include "dir-watch.h"
++#include "check.h"
+ #include <dbus/dbus-list.h>
+ #include <dbus/dbus-hash.h>
+ #include <dbus/dbus-credentials.h>
+@@ -65,6 +66,7 @@ struct BusContext
+   BusRegistry *registry;
+   BusPolicy *policy;
+   BusMatchmaker *matchmaker;
++  BusCheck *check;
+   BusLimits limits;
+   DBusRLimit *initial_fd_limit;
+   unsigned int fork : 1;
+@@ -988,6 +990,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;
+@@ -1112,6 +1118,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);
+@@ -1241,6 +1253,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)
+@@ -1456,6 +1474,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;
+@@ -1485,7 +1504,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)),
+@@ -1496,7 +1516,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 */
+@@ -1520,14 +1541,15 @@ 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
+-bus_context_check_security_policy (BusContext     *context,
+-                                   BusTransaction *transaction,
+-                                   DBusConnection *sender,
+-                                   DBusConnection *addressed_recipient,
+-                                   DBusConnection *proposed_recipient,
+-                                   DBusMessage    *message,
+-                                   DBusError      *error)
++BusResult
++bus_context_check_security_policy (BusContext          *context,
++                                   BusTransaction      *transaction,
++                                   DBusConnection      *sender,
++                                   DBusConnection      *addressed_recipient,
++                                   DBusConnection      *proposed_recipient,
++                                   DBusMessage         *message,
++                                   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);
+@@ -1564,7 +1587,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;
+@@ -1594,7 +1617,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;
+                     }
+                 }
+             }
+@@ -1621,11 +1644,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
+@@ -1642,7 +1665,7 @@ bus_context_check_security_policy (BusContext     *context,
+                                      dest ? dest : DBUS_SERVICE_DBUS,
+                                      src ? src : DBUS_SERVICE_DBUS,
+                                      error))
+-        return FALSE;
++        return BUS_RESULT_FALSE;
+       if (!bus_connection_is_active (sender))
+         {
+@@ -1656,7 +1679,7 @@ bus_context_check_security_policy (BusContext     *context,
+             {
+               _dbus_verbose ("security check allowing %s message\n",
+                              "Hello");
+-              return TRUE;
++              return BUS_RESULT_TRUE;
+             }
+           else
+             {
+@@ -1667,7 +1690,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;
+             }
+         }
+     }
+@@ -1716,20 +1739,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)
+     {
+@@ -1738,23 +1770,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 */
+@@ -1764,10 +1802,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
+@@ -1784,11 +1822,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 3fab59ff..dab7791f 100644
+--- a/bus/bus.h
++++ b/bus/bus.h
+@@ -44,6 +44,22 @@ typedef struct BusOwner             BusOwner;
+ typedef struct BusTransaction   BusTransaction;
+ typedef struct BusMatchmaker    BusMatchmaker;
+ typedef struct BusMatchRule     BusMatchRule;
++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
+ {
+@@ -97,6 +113,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,
+@@ -131,13 +148,14 @@ 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,
+-                                                                  BusTransaction   *transaction,
+-                                                                  DBusConnection   *sender,
+-                                                                  DBusConnection   *addressed_recipient,
+-                                                                  DBusConnection   *proposed_recipient,
+-                                                                  DBusMessage      *message,
+-                                                                  DBusError        *error);
++BusResult         bus_context_check_security_policy              (BusContext          *context,
++                                                                  BusTransaction      *transaction,
++                                                                  DBusConnection      *sender,
++                                                                  DBusConnection      *addressed_recipient,
++                                                                  DBusConnection      *proposed_recipient,
++                                                                  DBusMessage         *message,
++                                                                  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 00000000..5b72d31c
+--- /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 00000000..c3fcaf90
+--- /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 5db6b289..ea25f5e6 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 382a0141..9e026d10 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.c b/bus/config-parser.c
+index d9f6042c..a8c4ca5d 100644
+--- a/bus/config-parser.c
++++ b/bus/config-parser.c
+@@ -1172,7 +1172,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;
+@@ -1195,6 +1195,7 @@ append_rule_from_element (BusConfigParser   *parser,
+   const char *own_prefix;
+   const char *user;
+   const char *group;
++  const char *privilege;
+   BusPolicyRule *rule;
+   
+@@ -1222,6 +1223,7 @@ append_rule_from_element (BusConfigParser   *parser,
+                           "user", &user,
+                           "group", &group,
+                           "log", &log,
++                          "privilege", &privilege,
+                           NULL))
+     return FALSE;
+@@ -1230,6 +1232,7 @@ append_rule_from_element (BusConfigParser   *parser,
+         receive_interface || receive_member || receive_error || receive_sender ||
+         receive_type || receive_path || eavesdrop ||
+         send_requested_reply || receive_requested_reply ||
++        privilege ||
+         own || own_prefix || user || group))
+     {
+       dbus_set_error (error, DBUS_ERROR_FAILED,
+@@ -1246,7 +1249,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:
+@@ -1420,7 +1446,7 @@ append_rule_from_element (BusConfigParser   *parser,
+           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;
+       
+@@ -1502,7 +1528,7 @@ append_rule_from_element (BusConfigParser   *parser,
+           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;
+@@ -1532,7 +1558,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;
+@@ -1558,7 +1584,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;
+@@ -1573,7 +1599,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;
+@@ -1590,7 +1616,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;
+@@ -1605,7 +1631,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;
+@@ -1629,6 +1655,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:
+@@ -1703,7 +1733,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)
+@@ -1718,7 +1748,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)
+@@ -1727,6 +1757,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
+@@ -2088,6 +2133,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:
+@@ -2397,6 +2443,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:
+@@ -2862,6 +2909,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);
+diff --git a/bus/connection.c b/bus/connection.c
+index 02d6c220..eea50ecd 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
+@@ -451,6 +458,10 @@ free_connection_data (void *data)
+   
+   dbus_free (d->name);
+   
++#ifdef DBUS_ENABLE_CYNARA
++  free (d->cynara_session_id);
++#endif
++
+   dbus_free (d);
+ }
+@@ -1063,6 +1074,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,
+@@ -2289,6 +2316,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
+@@ -2326,9 +2354,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, &error))
++  res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
++                                           transaction,
++                                           NULL, connection, connection, message, &error,
++                                           NULL);
++  if (res == BUS_RESULT_FALSE)
+     {
+       if (!bus_transaction_capture_error_reply (transaction, &error, message))
+         {
+@@ -2342,6 +2372,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 8c68d0a0..a6e5dfde 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);
+@@ -122,6 +123,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 00000000..57a4c45c
+--- /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 00000000..c4728bb7
+--- /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 edfa1b44..05be3bdf 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,13 +65,17 @@ 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,
+-                                          &stack_error))
++                                          &stack_error,
++                                          &deferred_message);
++  if (result != BUS_RESULT_TRUE)
+     {
+       if (!bus_transaction_capture_error_reply (transaction, &stack_error,
+                                                 message))
+@@ -129,6 +134,7 @@ bus_dispatch_matches (BusTransaction *transaction,
+   BusMatchmaker *matchmaker;
+   DBusList *link;
+   BusContext *context;
++  BusDeferredMessage *deferred_message;
+   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+@@ -144,11 +150,21 @@ 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, error))
++      BusResult res;
++      res = bus_context_check_security_policy (context, transaction,
++                                               sender, addressed_recipient,
++                                               addressed_recipient,
++                                               message, 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,
+@@ -379,12 +395,24 @@ bus_dispatch (DBusConnection *connection,
+   if (service_name &&
+       strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
+     {
+-      if (!bus_context_check_security_policy (context, transaction,
+-                                              connection, NULL, NULL, message, &error))
++      BusDeferredMessage *deferred_message;
++      BusResult res;
++      res = bus_context_check_security_policy (context, transaction,
++                                               connection, NULL, NULL, message, &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/policy.c b/bus/policy.c
+index 082f3853..bcade176 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"
+@@ -32,7 +33,7 @@
+ BusPolicyRule*
+ bus_policy_rule_new (BusPolicyRuleType type,
+-                     dbus_bool_t       allow)
++                     BusPolicyRuleAccess access)
+ {
+   BusPolicyRule *rule;
+@@ -42,7 +43,7 @@ bus_policy_rule_new (BusPolicyRuleType type,
+   rule->type = type;
+   rule->refcount = 1;
+-  rule->allow = allow;
++  rule->access = access;
+   switch (rule->type)
+     {
+@@ -54,18 +55,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;
+@@ -117,7 +119,8 @@ bus_policy_rule_unref (BusPolicyRule *rule)
+         case BUS_POLICY_RULE_GROUP:
+           break;
+         }
+-      
++
++      dbus_free (rule->privilege);
+       dbus_free (rule);
+     }
+ }
+@@ -427,7 +430,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;
+@@ -862,18 +868,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
+    */
+@@ -881,7 +892,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)
+     {
+@@ -912,13 +923,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;
+             }
+@@ -926,7 +938,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;
+@@ -949,13 +961,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))
+@@ -1029,33 +1043,63 @@ 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:
++          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 &&
+@@ -1068,7 +1112,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)
+     {
+@@ -1091,19 +1135,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;
+@@ -1112,13 +1158,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;
+             }
+@@ -1126,7 +1173,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;
+@@ -1149,13 +1196,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))
+@@ -1230,14 +1277,42 @@ 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:
++          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;
+ }
+@@ -1289,7 +1364,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 d1d3e72b..e9f193af 100644
+--- a/bus/policy.h
++++ b/bus/policy.h
+@@ -39,6 +39,14 @@ typedef enum
+   BUS_POLICY_RULE_GROUP
+ } BusPolicyRuleType;
++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))
+@@ -49,8 +57,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
+@@ -106,7 +115,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);
+@@ -140,21 +149,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,
+-                                                      BusRegistry      *registry,
+-                                                      dbus_bool_t       requested_reply,
+-                                                      DBusConnection   *receiver,
+-                                                      DBusMessage      *message,
+-                                                      dbus_int32_t     *toggles,
+-                                                      dbus_bool_t      *log);
+-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_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);
++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);
+ 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 71e3515c..f3a2ffc1 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1873,6 +1873,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
+@@ -1952,6 +1963,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 914dd7f2..86882537 100644
+--- a/test/Makefile.am
++++ b/test/Makefile.am
+@@ -341,6 +341,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/multi-user.conf.in \
+       data/valid-config-files/systemd-activation.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 00000000..fad9f502
+--- /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 00000000..63c7ef25
+--- /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 00000000..ad714733
+--- /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 00000000..47ee8548
+--- /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>
+diff --git a/tools/dbus-send.c b/tools/dbus-send.c
+index 0dc1f5b3..76ddab3f 100644
+--- a/tools/dbus-send.c
++++ b/tools/dbus-send.c
+@@ -458,7 +458,7 @@ main (int argc, char *argv[])
+       char *arg;
+       char *c;
+       int type;
+-      int secondary_type;
++      int secondary_type = 0;
+       int container_type;
+       DBusMessageIter *target_iter;
+       DBusMessageIter container_iter;
+-- 
+2.14.3
+