Integration of asynchronous security checks
authorJacek Bukarewicz <j.bukarewicz@samsung.com>
Thu, 27 Nov 2014 17:11:05 +0000 (18:11 +0100)
committerAdrian Szyndela <adrian.s@samsung.com>
Fri, 19 Feb 2016 10:52:58 +0000 (11:52 +0100)
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.

Change-Id: I324b6ab68442e493853d8fe219c7a37fbd831872

14 files changed:
bus/Makefile.am
bus/bus.c
bus/bus.h
bus/check.c [new file with mode: 0644]
bus/check.h [new file with mode: 0644]
bus/connection.c
bus/connection.h
bus/cynara.c [new file with mode: 0644]
bus/cynara.h [new file with mode: 0644]
bus/dispatch.c
bus/policy.c
bus/policy.h
configure.ac
packaging/dbus.spec

index 73ada3c..9eb7456 100644 (file)
@@ -10,6 +10,7 @@ DBUS_BUS_LIBS = \
        $(ADT_LIBS) \
        $(NETWORK_libs) \
        $(LIBSMACK_LIBS) \
+       $(CYNARA_LIBS) \
        $(NULL)
 
 DBUS_LAUNCHER_LIBS = \
@@ -27,6 +28,7 @@ AM_CPPFLAGS = \
        -DDBUS_COMPILATION \
        -DDBUS_STATIC_BUILD \
        $(LIBSMACK_CFLAGS) \
+       $(CYNARA_CFLAGS) \
        $(NULL)
 
 # if assertions are enabled, improve backtraces
@@ -85,12 +87,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)                     \
index 128ae3c..f97dda3 100644 (file)
--- 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;
@@ -976,6 +978,10 @@ bus_context_new (const DBusString *config_file,
 
   bus_audit_init (context);
 
+  context->check = bus_check_new(context, error);
+  if (context->check == NULL)
+      goto failed;
+
   dbus_server_free_data_slot (&server_data_slot);
 
   return context;
@@ -1100,6 +1106,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);
@@ -1229,6 +1241,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)
@@ -1444,6 +1462,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;
@@ -1473,7 +1492,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\" "
+      "privilege=\"%s\" (%s)",
       complaint,
       matched_rules,
       dbus_message_type_to_string (dbus_message_get_type (message)),
@@ -1484,6 +1504,7 @@ complain_about_message (BusContext     *context,
       nonnull (dbus_message_get_error_name (message), "(unset)"),
       requested_reply,
       nonnull (dbus_message_get_destination (message), DBUS_SERVICE_DBUS),
+      nonnull (privilege, "(n/a)"),
       proposed_recipient_loginfo);
 
   /* If we hit OOM while setting the error, this will syslog "out of memory"
@@ -1508,14 +1529,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;
@@ -1524,6 +1546,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);
@@ -1552,7 +1575,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;
@@ -1582,7 +1605,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;
                     }
                 }
             }
@@ -1609,7 +1632,7 @@ 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");
             }
 
@@ -1644,7 +1667,7 @@ bus_context_check_security_policy (BusContext     *context,
             {
               _dbus_verbose ("security check allowing %s message\n",
                              "Hello");
-              return TRUE;
+              return BUS_RESULT_TRUE;
             }
           else
             {
@@ -1655,7 +1678,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;
             }
         }
     }
@@ -1704,20 +1727,32 @@ 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) {
+    switch (bus_client_policy_check_can_send (sender,
+                                              sender_policy,
+                                              context->registry,
+                                              requested_reply,
+                                              addressed_recipient,
+                                              proposed_recipient,
+                                              message, &toggles, &log, &privilege,
+                                              deferred_message))
+      {
+      case BUS_RESULT_TRUE:
+        break;
+      case 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;
+        break;
+      case BUS_RESULT_LATER:
+        return BUS_RESULT_LATER;
+        break;
+      }
+  }
 
   if (log)
     {
@@ -1726,24 +1761,31 @@ 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))
-    {
-      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;
-    }
+  if (recipient_policy) {
+      switch (bus_client_policy_check_can_receive (recipient_policy,
+                                                   context->registry,
+                                                   requested_reply,
+                                                   sender,
+                                                   addressed_recipient, proposed_recipient,
+                                                   message, &toggles, &privilege, deferred_message))
+      {
+      case BUS_RESULT_TRUE:
+        break;
+      case 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;
+      case BUS_RESULT_LATER:
+        return BUS_RESULT_LATER;
+      }
+  }
 
   /* See if limits on size have been exceeded */
   if (proposed_recipient &&
@@ -1752,10 +1794,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
@@ -1772,11 +1814,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
index 3fab59f..4e1ef6b 100644 (file)
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -44,6 +44,25 @@ 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;
+
+/**
+ * This uses BUS_RESULT_TRUE = 0 != TRUE intentionally, to trigger
+ * runtime failures where code uses a simple boolean check or
+ * comparison with TRUE/FALSE or returns TRUE/FALSE when it should use
+ * one of these enums. Such broken code unfortunately does not trigger
+ * compile time errors in C.
+ */
+typedef enum {
+  /** operation allowed or succeeded */
+  BUS_RESULT_TRUE,
+  /** operation denied or failed */
+  BUS_RESULT_FALSE,
+  /** no result yet, ask again later */
+  BUS_RESULT_LATER
+} BusResult;
 
 typedef struct
 {
@@ -97,6 +116,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 +151,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);
 void              bus_context_check_all_watches                  (BusContext       *context);
+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);
 
 #endif /* BUS_BUS_H */
diff --git a/bus/check.c b/bus/check.c
new file mode 100644 (file)
index 0000000..d2f418a
--- /dev/null
@@ -0,0 +1,215 @@
+/* -*- 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;
+  BusCynara *cynara;
+  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 (file)
index 0000000..c3fcaf9
--- /dev/null
@@ -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 */
index 95e20a6..418a688 100644 (file)
 #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);
 }
 
@@ -1037,6 +1048,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,
@@ -2300,10 +2327,14 @@ 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))
-    {
+  switch (bus_context_check_security_policy (bus_transaction_get_context (transaction),
+                                             transaction,
+                                             NULL, connection, connection, message, &error,
+                                             NULL))
+    {
+    case BUS_RESULT_TRUE:
+      break;
+    case BUS_RESULT_FALSE:
       if (!bus_transaction_capture_error_reply (transaction, &error, message))
         {
           bus_context_log (transaction->context, DBUS_SYSTEM_LOG_WARNING,
@@ -2315,6 +2346,11 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
        * message (see reasoning above) */
       dbus_error_free (&error);
       return TRUE;
+      break;
+    case BUS_RESULT_LATER:
+      _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
+      return TRUE;
+      break;
     }
 
   return bus_transaction_send (transaction, connection, message);
index 8c68d0a..a6e5dfd 100644 (file)
@@ -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 (file)
index 0000000..d659574
--- /dev/null
@@ -0,0 +1,332 @@
+/* -*- 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 <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;
+
+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;
+  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_initialize(&cynara->cynara, NULL, &status_callback, cynara);
+  if (ret != CYNARA_API_SUCCESS)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to initialize Cynara client");
+      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)
+    {
+      if (cynara->cynara != NULL)
+        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;
+  const 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;
+
+  _dbus_assert(connection != NULL);
+
+  if (dbus_connection_get_unix_user(connection, &uid) == FALSE)
+      return BUS_RESULT_FALSE;
+
+#ifdef DBUS_ENABLE_SMACK
+  if (dbus_connection_get_smack_label (connection, &label) == FALSE)
+      return BUS_RESULT_FALSE;
+#else
+#error Cannot get connection label with smack disabled
+#endif
+
+  session_id = bus_connection_get_cynara_session_id (connection);
+  if (session_id == NULL)
+    return BUS_RESULT_FALSE;
+
+  snprintf(user, sizeof(user), "%lu", uid);
+
+
+  result = cynara_async_check_cache(cynara->cynara, label, session_id, user, privilege);
+  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);
+    return BUS_RESULT_TRUE;
+
+  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);
+    return BUS_RESULT_FALSE;
+
+  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");
+         return BUS_RESULT_FALSE;
+       }
+
+    /* 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;
+        return BUS_RESULT_LATER;
+      }
+    else
+      {
+        _dbus_verbose("Error on cynara request create: %i\n", result);
+        bus_deferred_message_unref(deferred_message);
+        return BUS_RESULT_FALSE;
+      }
+    break;
+  default:
+    _dbus_verbose("Error when accessing Cynara cache: %i\n", result);
+    return BUS_RESULT_FALSE;
+  }
+
+#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 (file)
index 0000000..c4728bb
--- /dev/null
@@ -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);
index edfa1b4..21fe886 100644 (file)
@@ -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,13 @@ 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,
-                                          sender,
-                                          addressed_recipient,
-                                          connection,
-                                          message,
-                                          &stack_error))
+  result = bus_context_check_security_policy (context, transaction, sender, addressed_recipient,
+      connection, message, NULL, &deferred_message);
+
+  if (result != BUS_RESULT_TRUE)
     {
       if (!bus_transaction_capture_error_reply (transaction, &stack_error,
                                                 message))
@@ -129,6 +130,7 @@ bus_dispatch_matches (BusTransaction *transaction,
   BusMatchmaker *matchmaker;
   DBusList *link;
   BusContext *context;
+  BusDeferredMessage *deferred_message;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -144,11 +146,22 @@ 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))
-        return FALSE;
+      switch (bus_context_check_security_policy (context, transaction,
+                                                 sender, addressed_recipient,
+                                                 addressed_recipient,
+                                                 message, error,
+                                                 &deferred_message))
+        {
+          case BUS_RESULT_TRUE:
+            break;
+          case BUS_RESULT_FALSE:
+            return BUS_RESULT_FALSE;
+          case BUS_RESULT_LATER:
+            dbus_set_error (error,
+                            DBUS_ERROR_ACCESS_DENIED,
+                            "Rejecting message because time is needed to check security policy");
+            return BUS_RESULT_FALSE;
+        }
 
       if (dbus_message_contains_unix_fds (message) &&
           !dbus_connection_can_send_type (addressed_recipient,
@@ -379,11 +392,23 @@ 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;
+
+      switch (bus_context_check_security_policy (context, transaction,
+                                                 connection, NULL, NULL, message, &error,
+                                                 &deferred_message))
         {
+        case BUS_RESULT_TRUE:
+          break;
+        case BUS_RESULT_FALSE:
           _dbus_verbose ("Security policy rejected message\n");
           goto out;
+        case 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);
index 5af5b6b..825d754 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <config.h>
+#include "check.h"
 #include "policy.h"
 #include "services.h"
 #include "test.h"
@@ -992,17 +993,22 @@ 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
@@ -1011,7 +1017,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)
     {
@@ -1162,33 +1168,63 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
         }
 
       /* Use this rule */
-      allowed = rule->access == BUS_POLICY_RULE_ACCESS_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",
+                     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 &&
@@ -1201,7 +1237,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)
     {
@@ -1366,14 +1402,42 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
         }
       
       /* Use this rule */
-      allowed = rule->access == BUS_POLICY_RULE_ACCESS_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",
+                     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;
 }
 
 
index fd66bcb..08979d2 100644 (file)
@@ -152,21 +152,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,
index 1361b28..7a8e585 100644 (file)
@@ -1878,6 +1878,18 @@ fi
 AC_SUBST([LIBSMACK_CFLAGS])
 AC_SUBST([LIBSMACK_LIBS])
 
+#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.4.2 cynara-session >= 0.4.2],
+     [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
index e0ee7b9..40c14bc 100644 (file)
@@ -20,6 +20,8 @@ BuildRequires:  xmlto
 BuildRequires:  pkgconfig(libsystemd-daemon)
 BuildRequires:  pkgconfig(libsystemd-login)
 %endif
+BuildRequires:  pkgconfig(cynara-client-async)
+BuildRequires:  pkgconfig(cynara-session)
 Version:        1.8.2
 Release:        0
 Source0:        http://dbus.freedesktop.org/releases/dbus/dbus-%{version}.tar.gz
@@ -88,7 +90,8 @@ export V=1
 %endif
     --with-console-auth-dir=/var/run/dbus/at_console/                  \
     --with-systemdsystemunitdir=%{_unitdir}                            \
-    --enable-smack
+    --enable-smack \
+    --enable-cynara
 
 make %{?_smp_mflags}