summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacek Bukarewicz <j.bukarewicz@samsung.com>2014-11-27 18:11:05 +0100
committerJacek Bukarewicz <j.bukarewicz@samsung.com>2014-12-12 17:37:36 +0100
commit9e1bbf442bb9e565ff84c77e5a64c61eefa049d0 (patch)
treeeded5cbcd1057d678c8df075d8b1a8350d32be81
parent66b0a53f283a73a6cbabd3b56370dd162ab8cd12 (diff)
downloaddbus-9e1bbf442bb9e565ff84c77e5a64c61eefa049d0.tar.gz
dbus-9e1bbf442bb9e565ff84c77e5a64c61eefa049d0.tar.bz2
dbus-9e1bbf442bb9e565ff84c77e5a64c61eefa049d0.zip
Integration of 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: I324b6ab68442e493853d8fe219c7a37fbd831872
-rw-r--r--bus/Makefile.am6
-rw-r--r--bus/bus.c140
-rw-r--r--bus/bus.h61
-rw-r--r--bus/check.c215
-rw-r--r--bus/check.h68
-rw-r--r--bus/connection.c60
-rw-r--r--bus/connection.h5
-rw-r--r--bus/cynara.c332
-rw-r--r--bus/cynara.h37
-rw-r--r--bus/dispatch.c53
-rw-r--r--bus/policy.c122
-rw-r--r--bus/policy.h36
-rw-r--r--configure.ac12
-rw-r--r--packaging/dbus.spec5
14 files changed, 1013 insertions, 139 deletions
diff --git a/bus/Makefile.am b/bus/Makefile.am
index a5c39d0c..a0fea70b 100644
--- a/bus/Makefile.am
+++ b/bus/Makefile.am
@@ -8,6 +8,7 @@ DBUS_BUS_LIBS = \
$(ADT_LIBS) \
$(NETWORK_libs) \
$(LIBSMACK_LIBS) \
+ $(CYNARA_LIBS) \
$(NULL)
DBUS_LAUNCHER_LIBS = \
@@ -23,6 +24,7 @@ AM_CPPFLAGS = \
-DDBUS_COMPILATION \
-DDBUS_STATIC_BUILD \
$(LIBSMACK_CFLAGS) \
+ $(CYNARA_CFLAGS) \
$(NULL)
# if assertions are enabled, improve backtraces
@@ -62,12 +64,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 a6e004b1..a6dca003 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 <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-credentials.h>
@@ -62,6 +63,7 @@ struct BusContext
BusRegistry *registry;
BusPolicy *policy;
BusMatchmaker *matchmaker;
+ BusCheck *check;
BusLimits limits;
unsigned int fork : 1;
unsigned int syslog : 1;
@@ -938,6 +940,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;
@@ -1062,6 +1068,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);
@@ -1187,6 +1199,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)
@@ -1346,6 +1364,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;
@@ -1375,7 +1394,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)),
@@ -1386,6 +1406,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"
@@ -1410,14 +1431,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;
@@ -1426,6 +1448,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);
@@ -1453,7 +1476,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;
@@ -1477,11 +1500,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))
@@ -1507,7 +1530,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;
}
}
}
@@ -1524,7 +1547,7 @@ bus_context_check_security_policy (BusContext *context,
{
_dbus_verbose ("security check allowing %s message\n",
"Hello");
- return TRUE;
+ return BUS_RESULT_TRUE;
}
else
{
@@ -1535,7 +1558,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;
}
}
}
@@ -1584,20 +1607,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)
{
@@ -1606,24 +1641,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 &&
@@ -1632,10 +1674,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
@@ -1652,9 +1694,9 @@ 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;
}
diff --git a/bus/bus.h b/bus/bus.h
index 35978841..5f5a1c21 100644
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -30,19 +30,38 @@
#include <dbus/dbus-pipe.h>
#include <dbus/dbus-sysdeps.h>
-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;
+
+/**
+ * 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
{
@@ -95,6 +114,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,
@@ -118,12 +138,13 @@ 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);
+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 00000000..d2f418a7
--- /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 <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
index 00000000..c3fcaf90
--- /dev/null
+++ b/bus/check.h
@@ -0,0 +1,68 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* check.h Bus security policy runtime check
+ *
+ * Copyright (C) 2014 Intel, Inc.
+ * Copyright (c) 2014 Samsung Electronics, Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef BUS_CHECK_H
+#define BUS_CHECK_H
+
+#include "bus.h"
+#include "policy.h"
+
+
+typedef void (*BusCheckResponseFunc) (BusDeferredMessage *message,
+ BusResult result);
+
+typedef enum {
+ BUS_DEFERRED_MESSAGE_CHECK_SEND = 1 << 0,
+ BUS_DEFERRED_MESSAGE_CHECK_RECEIVE = 1 << 1,
+ BUS_DEFERRED_MESSAGE_CHECK_OWN = 1 << 2,
+} BusDeferredMessageStatus;
+
+
+BusCheck *bus_check_new (BusContext *context,
+ DBusError *error);
+BusCheck *bus_check_ref (BusCheck *check);
+void bus_check_unref (BusCheck *check);
+
+BusContext *bus_check_get_context (BusCheck *check);
+BusCynara *bus_check_get_cynara (BusCheck *check);
+BusResult bus_check_privilege (BusCheck *check,
+ DBusMessage *message,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusConnection *proposed_recipient,
+ const char *privilege,
+ BusDeferredMessageStatus check_type,
+ BusDeferredMessage **deferred_message);
+
+BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusConnection *proposed_recipient,
+ BusResult response);
+
+BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message);
+void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
+void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
+ BusResult result);
+#endif /* BUS_CHECK_H */
diff --git a/bus/connection.c b/bus/connection.c
index ea2d155a..32b6f468 100644
--- a/bus/connection.c
+++ b/bus/connection.c
@@ -33,6 +33,10 @@
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-timeout.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
@@ -102,6 +106,9 @@ typedef struct
int peak_match_rules;
int peak_bus_names;
#endif
+#ifdef DBUS_ENABLE_CYNARA
+ char *cynara_session_id;
+#endif
} BusConnectionData;
static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
@@ -115,8 +122,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;
@@ -315,7 +322,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
@@ -324,7 +331,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
@@ -333,7 +340,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
@@ -342,7 +349,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
@@ -351,7 +358,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
@@ -409,6 +416,10 @@ free_connection_data (void *data)
dbus_free (d->name);
+#ifdef DBUS_ENABLE_CYNARA
+ free (d->cynara_session_id);
+#endif
+
dbus_free (d);
}
@@ -915,6 +926,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,
@@ -2059,10 +2086,21 @@ 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))
- return TRUE;
+ switch (bus_context_check_security_policy (bus_transaction_get_context (transaction),
+ transaction,
+ NULL, connection, connection, message, NULL,
+ NULL))
+ {
+ case BUS_RESULT_TRUE:
+ break;
+ case BUS_RESULT_FALSE:
+ 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);
}
diff --git a/bus/connection.h b/bus/connection.h
index 9f4f9aea..ae6866ad 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 00000000..d6595747
--- /dev/null
+++ b/bus/cynara.c
@@ -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
index 00000000..c4728bb7
--- /dev/null
+++ b/bus/cynara.h
@@ -0,0 +1,37 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* cynara.h Cynara runtime privilege checking
+ *
+ * Copyright (c) 2014 Samsung Electronics, Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "bus.h"
+#include "check.h"
+
+BusCynara *bus_cynara_new (BusCheck *check, DBusError *error);
+BusCynara *bus_cynara_ref (BusCynara *cynara);
+void bus_cynara_unref (BusCynara *cynara);
+BusResult bus_cynara_check_privilege (BusCynara *cynara,
+ DBusMessage *message,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusConnection *proposed_recipient,
+ const char *privilege,
+ BusDeferredMessageStatus check_type,
+ BusDeferredMessage **deferred_message);
diff --git a/bus/dispatch.c b/bus/dispatch.c
index 7a61953f..556715d5 100644
--- a/bus/dispatch.c
+++ b/bus/dispatch.c
@@ -25,6 +25,7 @@
#include <config.h>
#include "dispatch.h"
+#include "check.h"
#include "connection.h"
#include "driver.h"
#include "services.h"
@@ -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,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,
@@ -273,11 +287,22 @@ 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);
diff --git a/bus/policy.c b/bus/policy.c
index 5af5b6b3..825d7544 100644
--- a/bus/policy.c
+++ b/bus/policy.c
@@ -22,6 +22,7 @@
*/
#include <config.h>
+#include "check.h"
#include "policy.h"
#include "services.h"
#include "test.h"
@@ -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;
}
diff --git a/bus/policy.h b/bus/policy.h
index fd66bcb5..08979d21 100644
--- a/bus/policy.h
+++ b/bus/policy.h
@@ -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,
diff --git a/configure.ac b/configure.ac
index f16ec5d2..ca2c47cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1759,6 +1759,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/versioninfo.rc
diff --git a/packaging/dbus.spec b/packaging/dbus.spec
index e0ee7b99..40c14bc0 100644
--- a/packaging/dbus.spec
+++ b/packaging/dbus.spec
@@ -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}