From 1b847a21fac05e88510fe37db63d0d9e4b72e633 Mon Sep 17 00:00:00 2001 From: José Bollo Date: Tue, 27 Mar 2018 11:05:46 +0200 Subject: dbus-cynara: Avoid dependency loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dependency loop appeared when compiling with DISTRO_FEATURE ptest. To avoid it, I restore the logic implemented before in meta-intel-iot-security. I also remove unless files. Bug-AGL: SPEC-1334 Change-Id: Ibe8b9359a65fec034df2534c5fceb4769e63aa99 Signed-off-by: José Bollo --- ...on-of-Cynara-asynchronous-security-checks.patch | 2253 -------------------- 1 file changed, 2253 deletions(-) delete mode 100644 meta-security/recipes-core/dbus-cynara/dbus-cynara/0004-Integration-of-Cynara-asynchronous-security-checks.patch (limited to 'meta-security/recipes-core/dbus-cynara/dbus-cynara/0004-Integration-of-Cynara-asynchronous-security-checks.patch') diff --git a/meta-security/recipes-core/dbus-cynara/dbus-cynara/0004-Integration-of-Cynara-asynchronous-security-checks.patch b/meta-security/recipes-core/dbus-cynara/dbus-cynara/0004-Integration-of-Cynara-asynchronous-security-checks.patch deleted file mode 100644 index 70d5fc9d7..000000000 --- a/meta-security/recipes-core/dbus-cynara/dbus-cynara/0004-Integration-of-Cynara-asynchronous-security-checks.patch +++ /dev/null @@ -1,2253 +0,0 @@ -From 4dcfb02f17247ff9de966b62182cd2e08f301238 Mon Sep 17 00:00:00 2001 -From: Jacek Bukarewicz -Date: Thu, 27 Nov 2014 18:11:05 +0100 -Subject: [PATCH 4/8] Integration of Cynara asynchronous security checks - -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: I9bcbce34577e5dc2a3cecf6233a0a2b0e43e1108 ---- - bus/Makefile.am | 6 + - bus/bus.c | 134 +++++--- - bus/bus.h | 58 ++-- - bus/check.c | 215 ++++++++++++ - 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 | 5 + - bus/cynara.c | 374 +++++++++++++++++++++ - bus/cynara.h | 37 ++ - bus/dispatch.c | 51 ++- - bus/policy.c | 193 +++++++---- - bus/policy.h | 51 ++- - configure.ac | 13 + - 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 + - 22 files changed, 1211 insertions(+), 180 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 f335e30..b057d6b 100644 ---- a/bus/Makefile.am -+++ b/bus/Makefile.am -@@ -7,6 +7,7 @@ DBUS_BUS_LIBS = \ - $(THREAD_LIBS) \ - $(ADT_LIBS) \ - $(NETWORK_libs) \ -+ $(CYNARA_LIBS) \ - $(NULL) - - DBUS_LAUNCHER_LIBS = \ -@@ -21,6 +22,7 @@ AM_CPPFLAGS = \ - -DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \ - -DDBUS_COMPILATION \ - -DDBUS_STATIC_BUILD \ -+ $(CYNARA_CFLAGS) \ - $(NULL) - - # if assertions are enabled, improve backtraces -@@ -60,12 +62,16 @@ BUS_SOURCES= \ - activation-exit-codes.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 f0d980e..ac9ea8d 100644 ---- a/bus/bus.c -+++ b/bus/bus.c -@@ -35,6 +35,7 @@ - #include "signals.h" - #include "selinux.h" - #include "dir-watch.h" -+#include "check.h" - #include - #include - #include -@@ -63,6 +64,7 @@ struct BusContext - BusRegistry *registry; - BusPolicy *policy; - BusMatchmaker *matchmaker; -+ BusCheck *check; - BusLimits limits; - DBusRLimit *initial_fd_limit; - unsigned int fork : 1; -@@ -962,6 +964,10 @@ bus_context_new (const DBusString *config_file, - #endif - } - -+ context->check = bus_check_new(context, error); -+ if (context->check == NULL) -+ goto failed; -+ - dbus_server_free_data_slot (&server_data_slot); - - return context; -@@ -1086,6 +1092,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); -@@ -1215,6 +1227,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) -@@ -1386,6 +1404,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; -@@ -1415,7 +1434,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)), -@@ -1426,7 +1446,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 */ -@@ -1450,14 +1471,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 *dest; - BusClientPolicy *sender_policy; -@@ -1466,6 +1488,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); - dest = dbus_message_get_destination (message); -@@ -1493,7 +1516,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; -@@ -1517,11 +1540,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; - } - - if (bus_connection_is_active (sender)) -@@ -1547,7 +1570,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; - } - } - } -@@ -1564,7 +1587,7 @@ bus_context_check_security_policy (BusContext *context, - { - _dbus_verbose ("security check allowing %s message\n", - "Hello"); -- return TRUE; -+ return BUS_RESULT_TRUE; - } - else - { -@@ -1575,7 +1598,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; - } - } - } -@@ -1624,20 +1647,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) - { -@@ -1646,23 +1678,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 */ -@@ -1672,10 +1710,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 -@@ -1692,11 +1730,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 dac6ea5..78084dd 100644 ---- a/bus/bus.h -+++ b/bus/bus.h -@@ -30,19 +30,35 @@ - #include - #include - --typedef struct BusActivation BusActivation; --typedef struct BusConnections BusConnections; --typedef struct BusContext BusContext; --typedef struct BusPolicy BusPolicy; --typedef struct BusClientPolicy BusClientPolicy; --typedef struct BusPolicyRule BusPolicyRule; --typedef struct BusRegistry BusRegistry; --typedef struct BusSELinuxID BusSELinuxID; --typedef struct BusService BusService; --typedef struct BusOwner BusOwner; --typedef struct BusTransaction BusTransaction; --typedef struct BusMatchmaker BusMatchmaker; --typedef struct BusMatchRule BusMatchRule; -+typedef struct BusActivation BusActivation; -+typedef struct BusConnections BusConnections; -+typedef struct BusContext BusContext; -+typedef struct BusPolicy BusPolicy; -+typedef struct BusClientPolicy BusClientPolicy; -+typedef struct BusPolicyRule BusPolicyRule; -+typedef struct BusRegistry BusRegistry; -+typedef struct BusSELinuxID BusSELinuxID; -+typedef struct BusService BusService; -+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 - { -@@ -96,6 +112,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, -@@ -121,13 +138,14 @@ void bus_context_log (BusContext - DBusSystemLogSeverity severity, - const char *msg, - ...); --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 -index 0000000..d2f418a ---- /dev/null -+++ b/bus/check.c -@@ -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 -+#include "check.h" -+#include "connection.h" -+#include "dispatch.h" -+#include "cynara.h" -+#include "utils.h" -+#include -+#include -+#include -+ -+ -+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 -index 0000000..c3fcaf9 ---- /dev/null -+++ b/bus/check.h -@@ -0,0 +1,68 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* check.h Bus security policy runtime check -+ * -+ * Copyright (C) 2014 Intel, Inc. -+ * Copyright (c) 2014 Samsung Electronics, Ltd. -+ * -+ * Licensed under the Academic Free License version 2.1 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ */ -+ -+#ifndef BUS_CHECK_H -+#define BUS_CHECK_H -+ -+#include "bus.h" -+#include "policy.h" -+ -+ -+typedef void (*BusCheckResponseFunc) (BusDeferredMessage *message, -+ BusResult result); -+ -+typedef enum { -+ BUS_DEFERRED_MESSAGE_CHECK_SEND = 1 << 0, -+ BUS_DEFERRED_MESSAGE_CHECK_RECEIVE = 1 << 1, -+ BUS_DEFERRED_MESSAGE_CHECK_OWN = 1 << 2, -+} BusDeferredMessageStatus; -+ -+ -+BusCheck *bus_check_new (BusContext *context, -+ DBusError *error); -+BusCheck *bus_check_ref (BusCheck *check); -+void bus_check_unref (BusCheck *check); -+ -+BusContext *bus_check_get_context (BusCheck *check); -+BusCynara *bus_check_get_cynara (BusCheck *check); -+BusResult bus_check_privilege (BusCheck *check, -+ DBusMessage *message, -+ DBusConnection *sender, -+ DBusConnection *addressed_recipient, -+ DBusConnection *proposed_recipient, -+ const char *privilege, -+ BusDeferredMessageStatus check_type, -+ BusDeferredMessage **deferred_message); -+ -+BusDeferredMessage *bus_deferred_message_new (DBusMessage *message, -+ DBusConnection *sender, -+ DBusConnection *addressed_recipient, -+ DBusConnection *proposed_recipient, -+ BusResult response); -+ -+BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message); -+void bus_deferred_message_unref (BusDeferredMessage *deferred_message); -+void bus_deferred_message_response_received (BusDeferredMessage *deferred_message, -+ BusResult result); -+#endif /* BUS_CHECK_H */ -diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c -index c522ff4..1cfe4c8 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; -@@ -155,6 +159,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 186bf4c..bff6fdb 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 ee2d4e7..73c9e6f 100644 ---- a/bus/config-parser.c -+++ b/bus/config-parser.c -@@ -1150,7 +1150,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; -@@ -1173,6 +1173,7 @@ append_rule_from_element (BusConfigParser *parser, - const char *own_prefix; - const char *user; - const char *group; -+ const char *privilege; - - BusPolicyRule *rule; - -@@ -1200,6 +1201,7 @@ append_rule_from_element (BusConfigParser *parser, - "user", &user, - "group", &group, - "log", &log, -+ "privilege", &privilege, - NULL)) - return FALSE; - -@@ -1208,6 +1210,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, -@@ -1224,7 +1227,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: -@@ -1398,7 +1424,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; - -@@ -1480,7 +1506,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; - -@@ -1510,7 +1536,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; - -@@ -1536,7 +1562,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; - -@@ -1551,7 +1577,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; - -@@ -1568,7 +1594,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; - -@@ -1583,7 +1609,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; - -@@ -1607,6 +1633,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: -@@ -1681,7 +1711,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) -@@ -1696,7 +1726,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) -@@ -1707,6 +1737,21 @@ start_policy_child (BusConfigParser *parser, - - 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 - { - dbus_set_error (error, DBUS_ERROR_FAILED, -@@ -2066,6 +2111,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: -@@ -2365,6 +2411,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: -@@ -2829,6 +2876,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 7107434..a6d87e5 100644 ---- a/bus/connection.c -+++ b/bus/connection.c -@@ -34,6 +34,10 @@ - #include - #include - #include -+#ifdef DBUS_ENABLE_CYNARA -+#include -+#include -+#endif - - /* Trim executed commands to this length; we want to keep logs readable */ - #define MAX_LOG_COMMAND_LEN 50 -@@ -105,6 +109,9 @@ typedef struct - #endif - int n_pending_unix_fds; - DBusTimeout *pending_unix_fds_timeout; -+#ifdef DBUS_ENABLE_CYNARA -+ char *cynara_session_id; -+#endif - } BusConnectionData; - - static dbus_bool_t bus_pending_reply_expired (BusExpireList *list, -@@ -118,8 +125,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; - -@@ -331,7 +338,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 -@@ -340,7 +347,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 -@@ -349,7 +356,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 -@@ -358,7 +365,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 -@@ -367,7 +374,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 -@@ -425,6 +432,10 @@ free_connection_data (void *data) - - dbus_free (d->name); - -+#ifdef DBUS_ENABLE_CYNARA -+ free (d->cynara_session_id); -+#endif -+ - dbus_free (d); - } - -@@ -984,6 +995,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, -@@ -2104,6 +2131,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction, - DBusConnection *connection, - DBusMessage *message) - { -+ BusResult res; - /* We have to set the sender to the driver, and have - * to check security policy since it was not done in - * dispatch.c -@@ -2132,10 +2160,18 @@ bus_transaction_send_from_driver (BusTransaction *transaction, - /* If security policy doesn't allow the message, we silently - * eat it; the driver doesn't care about getting a reply. - */ -- if (!bus_context_check_security_policy (bus_transaction_get_context (transaction), -- transaction, -- NULL, connection, connection, message, NULL)) -+ res = bus_context_check_security_policy (bus_transaction_get_context (transaction), -+ transaction, -+ NULL, connection, connection, message, NULL, -+ NULL); -+ -+ if (res == BUS_RESULT_FALSE) - return TRUE; -+ else if (res == BUS_RESULT_LATER) -+ { -+ _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n"); -+ return TRUE; -+ } - - return bus_transaction_send (transaction, connection, message); - } -diff --git a/bus/connection.h b/bus/connection.h -index 6fbcd38..7433746 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); -@@ -116,6 +117,10 @@ dbus_bool_t bus_connection_get_unix_groups (DBusConnection *connecti - DBusError *error); - BusClientPolicy* bus_connection_get_policy (DBusConnection *connection); - -+#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 */ - - typedef void (* BusTransactionCancelFunction) (void *data); -diff --git a/bus/cynara.c b/bus/cynara.c -new file mode 100644 -index 0000000..57a4c45 ---- /dev/null -+++ b/bus/cynara.c -@@ -0,0 +1,374 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* cynara.c Cynara runtime privilege checking -+ * -+ * Copyright (c) 2014 Samsung Electronics, Ltd. -+ * -+ * Licensed under the Academic Free License version 2.1 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ */ -+ -+#include -+#include "cynara.h" -+#include "check.h" -+#include "utils.h" -+ -+#include -+ -+#include -+#include -+#include -+#include -+#ifdef DBUS_ENABLE_CYNARA -+#include -+#endif -+ -+ -+#ifdef DBUS_ENABLE_CYNARA -+typedef struct BusCynara -+{ -+ int refcount; -+ -+ BusContext *context; -+ BusCheck *check; -+ cynara_async *cynara; -+ DBusWatch *cynara_watch; -+} BusCynara; -+ -+#define USE_CYNARA_CACHE 1 -+#ifdef USE_CYNARA_CACHE -+#define CYNARA_CACHE_SIZE 1000 -+#endif -+ -+static dbus_bool_t bus_cynara_watch_callback(DBusWatch *watch, -+ unsigned int flags, -+ void *data); -+ -+static void status_callback(int old_fd, -+ int new_fd, -+ cynara_async_status status, -+ void *user_status_data); -+static void bus_cynara_check_response_callback (cynara_check_id check_id, -+ cynara_async_call_cause cause, -+ int response, -+ void *user_response_data); -+#endif -+ -+ -+BusCynara * -+bus_cynara_new(BusCheck *check, DBusError *error) -+{ -+#ifdef DBUS_ENABLE_CYNARA -+ BusContext *context; -+ BusCynara *cynara; -+ cynara_async_configuration *conf = NULL; -+ int ret; -+ -+ cynara = dbus_new(BusCynara, 1); -+ if (cynara == NULL) -+ { -+ BUS_SET_OOM(error); -+ return NULL; -+ } -+ -+ context = bus_check_get_context(check); -+ -+ cynara->refcount = 1; -+ cynara->check = check; -+ cynara->context = context; -+ cynara->cynara_watch = NULL; -+ -+ ret = cynara_async_configuration_create(&conf); -+ if (ret != CYNARA_API_SUCCESS) -+ { -+ dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to create Cynara configuration"); -+ goto out; -+ } -+ -+#ifdef CYNARA_CACHE_SIZE -+ ret = cynara_async_configuration_set_cache_size(conf, CYNARA_CACHE_SIZE); -+ if (ret != CYNARA_API_SUCCESS) -+ { -+ dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to Cynara cache size"); -+ goto out; -+ } -+#endif -+ -+ ret = cynara_async_initialize(&cynara->cynara, conf, &status_callback, cynara); -+ if (ret != CYNARA_API_SUCCESS) -+ { -+ dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to initialize Cynara client"); -+ goto out; -+ } -+ -+out: -+ cynara_async_configuration_destroy(conf); -+ if (ret != CYNARA_API_SUCCESS) -+ { -+ dbus_free(cynara); -+ return NULL; -+ } -+ -+ return cynara; -+#else -+ return NULL; -+#endif -+} -+ -+BusCynara * -+bus_cynara_ref (BusCynara *cynara) -+{ -+#ifdef DBUS_ENABLE_CYNARA -+ _dbus_assert (cynara->refcount > 0); -+ cynara->refcount += 1; -+ -+ return cynara; -+#else -+ return NULL; -+#endif -+} -+ -+void -+bus_cynara_unref (BusCynara *cynara) -+{ -+#ifdef DBUS_ENABLE_CYNARA -+ _dbus_assert (cynara->refcount > 0); -+ -+ cynara->refcount -= 1; -+ -+ if (cynara->refcount == 0) -+ { -+ cynara_async_finish(cynara->cynara); -+ dbus_free(cynara); -+ } -+#endif -+} -+ -+BusResult -+bus_cynara_check_privilege (BusCynara *cynara, -+ DBusMessage *message, -+ DBusConnection *sender, -+ DBusConnection *addressed_recipient, -+ DBusConnection *proposed_recipient, -+ const char *privilege, -+ BusDeferredMessageStatus check_type, -+ BusDeferredMessage **deferred_message_param) -+{ -+#ifdef DBUS_ENABLE_CYNARA -+ int result; -+ unsigned long uid; -+ char *label; -+ const char *session_id; -+ char user[32]; -+ cynara_check_id check_id; -+ DBusConnection *connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender; -+ BusDeferredMessage *deferred_message; -+ BusResult ret; -+ -+ _dbus_assert(connection != NULL); -+ -+ if (dbus_connection_get_unix_user(connection, &uid) == FALSE) -+ return BUS_RESULT_FALSE; -+ -+ if (_dbus_connection_get_linux_security_label(connection, &label) == FALSE || label == NULL) -+ { -+ _dbus_warn("Failed to obtain security label for connection\n"); -+ return BUS_RESULT_FALSE; -+ } -+ -+ session_id = bus_connection_get_cynara_session_id (connection); -+ if (session_id == NULL) -+ { -+ ret = BUS_RESULT_FALSE; -+ goto out; -+ } -+ -+ snprintf(user, sizeof(user), "%lu", uid); -+ -+#if USE_CYNARA_CACHE -+ result = cynara_async_check_cache(cynara->cynara, label, session_id, user, privilege); -+#else -+ result = CYNARA_API_CACHE_MISS; -+#endif -+ -+ switch (result) -+ { -+ case CYNARA_API_ACCESS_ALLOWED: -+ _dbus_verbose("Cynara: got ALLOWED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n", -+ label, session_id, user, privilege); -+ ret = BUS_RESULT_TRUE; -+ break; -+ -+ case CYNARA_API_ACCESS_DENIED: -+ _dbus_verbose("Cynara: got DENIED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n", -+ label, session_id, user, privilege); -+ ret = BUS_RESULT_FALSE; -+ break; -+ -+ case CYNARA_API_CACHE_MISS: -+ deferred_message = bus_deferred_message_new(message, sender, addressed_recipient, -+ proposed_recipient, BUS_RESULT_LATER); -+ if (deferred_message == NULL) -+ { -+ _dbus_verbose("Failed to allocate memory for deferred message\n"); -+ ret = BUS_RESULT_FALSE; -+ goto out; -+ } -+ -+ /* callback is supposed to unref deferred_message*/ -+ result = cynara_async_create_request(cynara->cynara, label, session_id, user, privilege, &check_id, -+ &bus_cynara_check_response_callback, deferred_message); -+ if (result == CYNARA_API_SUCCESS) -+ { -+ _dbus_verbose("Created Cynara request: client=%s session_id=%s user=%s privilege=%s check_id=%u " -+ "deferred_message=%p\n", label, session_id, user, privilege, (unsigned int)check_id, deferred_message); -+ if (deferred_message_param != NULL) -+ *deferred_message_param = deferred_message; -+ ret = BUS_RESULT_LATER; -+ } -+ else -+ { -+ _dbus_verbose("Error on cynara request create: %i\n", result); -+ bus_deferred_message_unref(deferred_message); -+ ret = BUS_RESULT_FALSE; -+ } -+ break; -+ default: -+ _dbus_verbose("Error when accessing Cynara cache: %i\n", result); -+ ret = BUS_RESULT_FALSE; -+ } -+out: -+ dbus_free(label); -+ return ret; -+ -+#else -+ return BUS_RESULT_FALSE; -+#endif -+} -+ -+ -+ -+#ifdef DBUS_ENABLE_CYNARA -+static void -+status_callback(int old_fd, int new_fd, cynara_async_status status, -+ void *user_status_data) -+{ -+ BusCynara *cynara = (BusCynara *)user_status_data; -+ DBusLoop *loop = bus_context_get_loop(cynara->context); -+ -+ if (cynara->cynara_watch != NULL) -+ { -+ _dbus_loop_remove_watch(loop, cynara->cynara_watch); -+ _dbus_watch_invalidate(cynara->cynara_watch); -+ _dbus_watch_unref(cynara->cynara_watch); -+ cynara->cynara_watch = NULL; -+ } -+ -+ if (new_fd != -1) -+ { -+ unsigned int flags; -+ DBusWatch *watch; -+ -+ switch (status) -+ { -+ case CYNARA_STATUS_FOR_READ: -+ flags = DBUS_WATCH_READABLE; -+ break; -+ case CYNARA_STATUS_FOR_RW: -+ flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE; -+ break; -+ default: -+ /* Cynara passed unknown status - warn and add RW watch */ -+ _dbus_verbose("Cynara passed unknown status value: 0x%08X\n", (unsigned int)status); -+ flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE; -+ break; -+ } -+ -+ watch = _dbus_watch_new(new_fd, flags, TRUE, &bus_cynara_watch_callback, cynara, NULL); -+ if (watch != NULL) -+ { -+ if (_dbus_loop_add_watch(loop, watch) == TRUE) -+ { -+ cynara->cynara_watch = watch; -+ return; -+ } -+ -+ _dbus_watch_invalidate(watch); -+ _dbus_watch_unref(watch); -+ } -+ -+ /* It seems like not much can be done at this point. Cynara events won't be processed -+ * until next Cynara function call triggering status callback */ -+ _dbus_verbose("Failed to add dbus watch\n"); -+ } -+} -+ -+static dbus_bool_t -+bus_cynara_watch_callback(DBusWatch *watch, -+ unsigned int flags, -+ void *data) -+{ -+ BusCynara *cynara = (BusCynara *)data; -+ int result = cynara_async_process(cynara->cynara); -+ if (result != CYNARA_API_SUCCESS) -+ _dbus_verbose("cynara_async_process returned %d\n", result); -+ -+ return result != CYNARA_API_OUT_OF_MEMORY ? TRUE : FALSE; -+} -+ -+static inline const char * -+call_cause_to_string(cynara_async_call_cause cause) -+{ -+ switch (cause) -+ { -+ case CYNARA_CALL_CAUSE_ANSWER: -+ return "ANSWER"; -+ case CYNARA_CALL_CAUSE_CANCEL: -+ return "CANCEL"; -+ case CYNARA_CALL_CAUSE_FINISH: -+ return "FINSIH"; -+ case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE: -+ return "SERVICE NOT AVAILABLE"; -+ default: -+ return "INVALID"; -+ } -+} -+ -+static void -+bus_cynara_check_response_callback (cynara_check_id check_id, -+ cynara_async_call_cause cause, -+ int response, -+ void *user_response_data) -+{ -+ BusDeferredMessage *deferred_message = user_response_data; -+ BusResult result; -+ -+ _dbus_verbose("Cynara callback: check_id=%u, cause=%s response=%i response_data=%p\n", -+ (unsigned int)check_id, call_cause_to_string(cause), response, user_response_data); -+ -+ if (deferred_message == NULL) -+ return; -+ -+ if (cause == CYNARA_CALL_CAUSE_ANSWER && response == CYNARA_API_ACCESS_ALLOWED) -+ result = BUS_RESULT_TRUE; -+ else -+ result = BUS_RESULT_FALSE; -+ -+ bus_deferred_message_response_received(deferred_message, result); -+ bus_deferred_message_unref(deferred_message); -+} -+ -+#endif /* DBUS_ENABLE_CYNARA */ -diff --git a/bus/cynara.h b/bus/cynara.h -new file mode 100644 -index 0000000..c4728bb ---- /dev/null -+++ b/bus/cynara.h -@@ -0,0 +1,37 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* cynara.h Cynara runtime privilege checking -+ * -+ * Copyright (c) 2014 Samsung Electronics, Ltd. -+ * -+ * Licensed under the Academic Free License version 2.1 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ */ -+ -+#include "bus.h" -+#include "check.h" -+ -+BusCynara *bus_cynara_new (BusCheck *check, DBusError *error); -+BusCynara *bus_cynara_ref (BusCynara *cynara); -+void bus_cynara_unref (BusCynara *cynara); -+BusResult bus_cynara_check_privilege (BusCynara *cynara, -+ DBusMessage *message, -+ DBusConnection *sender, -+ DBusConnection *addressed_recipient, -+ DBusConnection *proposed_recipient, -+ const char *privilege, -+ BusDeferredMessageStatus check_type, -+ BusDeferredMessage **deferred_message); -diff --git a/bus/dispatch.c b/bus/dispatch.c -index 7a61953..ce4076d 100644 ---- a/bus/dispatch.c -+++ b/bus/dispatch.c -@@ -25,6 +25,7 @@ - - #include - #include "dispatch.h" -+#include "check.h" - #include "connection.h" - #include "driver.h" - #include "services.h" -@@ -56,13 +57,14 @@ send_one_message (DBusConnection *connection, - BusTransaction *transaction, - DBusError *error) - { -- if (!bus_context_check_security_policy (context, transaction, -- sender, -- addressed_recipient, -- connection, -- message, -- NULL)) -- return TRUE; /* silently don't send it */ -+ BusDeferredMessage *deferred_message; -+ BusResult result; -+ -+ result = bus_context_check_security_policy (context, transaction, sender, addressed_recipient, -+ connection, message, NULL, &deferred_message); -+ -+ if (result != BUS_RESULT_TRUE) -+ return TRUE; /* silently don't send it */ - - if (dbus_message_contains_unix_fds(message) && - !dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD)) -@@ -92,6 +94,7 @@ bus_dispatch_matches (BusTransaction *transaction, - BusMatchmaker *matchmaker; - DBusList *link; - BusContext *context; -+ BusDeferredMessage *deferred_message; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - -@@ -107,11 +110,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, -@@ -273,12 +286,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 082f385..ec888df 100644 ---- a/bus/policy.c -+++ b/bus/policy.c -@@ -22,6 +22,7 @@ - */ - - #include -+#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 and -+ 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", -+ 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", -+ 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 d1d3e72..e9f193a 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 eb803af..b131f30 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1748,6 +1748,18 @@ if test "x$enable_stats" = xyes; then - [Define to enable bus daemon usage statistics]) - fi - -+#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/versioninfo.rc -@@ -1778,6 +1790,7 @@ dbus-1.pc - dbus-1-uninstalled.pc - test/data/valid-config-files/debug-allow-all.conf - test/data/valid-config-files/debug-allow-all-sha1.conf -+test/data/valid-config-files/debug-check-some.conf - test/data/valid-config-files/incoming-limit.conf - test/data/valid-config-files-system/debug-allow-all-pass.conf - test/data/valid-config-files-system/debug-allow-all-fail.conf -diff --git a/test/Makefile.am b/test/Makefile.am -index e0ed3c8..ab63edc 100644 ---- a/test/Makefile.am -+++ b/test/Makefile.am -@@ -254,6 +254,7 @@ in_data = \ - data/valid-config-files-system/debug-allow-all-pass.conf.in \ - data/valid-config-files/debug-allow-all-sha1.conf.in \ - data/valid-config-files/debug-allow-all.conf.in \ -+ data/valid-config-files/debug-check-some.conf.in \ - data/valid-config-files/incoming-limit.conf.in \ - data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \ - data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \ -diff --git a/test/data/invalid-config-files/badcheck-1.conf b/test/data/invalid-config-files/badcheck-1.conf -new file mode 100644 -index 0000000..fad9f50 ---- /dev/null -+++ b/test/data/invalid-config-files/badcheck-1.conf -@@ -0,0 +1,9 @@ -+ -+ -+ mybususer -+ unix:path=/foo/bar -+ -+ -+ -+ -diff --git a/test/data/invalid-config-files/badcheck-2.conf b/test/data/invalid-config-files/badcheck-2.conf -new file mode 100644 -index 0000000..63c7ef2 ---- /dev/null -+++ b/test/data/invalid-config-files/badcheck-2.conf -@@ -0,0 +1,9 @@ -+ -+ -+ mybususer -+ unix:path=/foo/bar -+ -+ -+ -+ -diff --git a/test/data/valid-config-files/check-1.conf b/test/data/valid-config-files/check-1.conf -new file mode 100644 -index 0000000..ad71473 ---- /dev/null -+++ b/test/data/valid-config-files/check-1.conf -@@ -0,0 +1,9 @@ -+ -+ -+ mybususer -+ unix:path=/foo/bar -+ -+ -+ -+ -diff --git a/test/data/valid-config-files/debug-check-some.conf.in b/test/data/valid-config-files/debug-check-some.conf.in -new file mode 100644 -index 0000000..47ee854 ---- /dev/null -+++ b/test/data/valid-config-files/debug-check-some.conf.in -@@ -0,0 +1,18 @@ -+ -+ -+ -+ -+ debug-pipe:name=test-server -+ @TEST_LISTEN@ -+ @DBUS_TEST_DATA@/valid-service-files -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ --- -2.1.4 - -- cgit 1.2.3-korg