From 04f201e0fc3d81113113fff490e279d5d7eec5c5 Mon Sep 17 00:00:00 2001 From: Jacek Bukarewicz Date: Thu, 27 Nov 2014 18:11:05 +0100 Subject: [PATCH] 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 --- bus/Makefile.am | 6 + bus/bus.c | 138 ++++++++++++++-------- bus/bus.h | 35 ++++-- bus/check.c | 215 ++++++++++++++++++++++++++++++++++ bus/check.h | 68 +++++++++++ bus/connection.c | 58 +++++++-- bus/connection.h | 4 + bus/cynara.c | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++ bus/cynara.h | 37 ++++++ bus/dispatch.c | 51 ++++++-- bus/policy.c | 122 ++++++++++++++----- bus/policy.h | 36 +++--- configure.ac | 12 ++ packaging/dbus.spec | 5 +- 14 files changed, 995 insertions(+), 124 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 diff --git a/bus/Makefile.am b/bus/Makefile.am index 73ada3c..9eb7456 100644 --- a/bus/Makefile.am +++ b/bus/Makefile.am @@ -10,6 +10,7 @@ DBUS_BUS_LIBS = \ $(ADT_LIBS) \ $(NETWORK_libs) \ $(LIBSMACK_LIBS) \ + $(CYNARA_LIBS) \ $(NULL) DBUS_LAUNCHER_LIBS = \ @@ -27,6 +28,7 @@ AM_CPPFLAGS = \ -DDBUS_COMPILATION \ -DDBUS_STATIC_BUILD \ $(LIBSMACK_CFLAGS) \ + $(CYNARA_CFLAGS) \ $(NULL) # if assertions are enabled, improve backtraces @@ -85,12 +87,16 @@ BUS_SOURCES= \ audit.h \ bus.c \ bus.h \ + check.c \ + check.h \ config-parser.c \ config-parser.h \ config-parser-common.c \ config-parser-common.h \ connection.c \ connection.h \ + cynara.c \ + cynara.h \ desktop-file.c \ desktop-file.h \ $(DIR_WATCH_SOURCE) \ diff --git a/bus/bus.c b/bus/bus.c index 128ae3c..f97dda3 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -37,6 +37,7 @@ #include "apparmor.h" #include "audit.h" #include "dir-watch.h" +#include "check.h" #include #include #include @@ -65,6 +66,7 @@ struct BusContext BusRegistry *registry; BusPolicy *policy; BusMatchmaker *matchmaker; + BusCheck *check; BusLimits limits; DBusRLimit *initial_fd_limit; unsigned int fork : 1; @@ -976,6 +978,10 @@ bus_context_new (const DBusString *config_file, bus_audit_init (context); + context->check = bus_check_new(context, error); + if (context->check == NULL) + goto failed; + dbus_server_free_data_slot (&server_data_slot); return context; @@ -1100,6 +1106,12 @@ bus_context_unref (BusContext *context) bus_context_shutdown (context); + if (context->check) + { + bus_check_unref(context->check); + context->check = NULL; + } + if (context->connections) { bus_connections_unref (context->connections); @@ -1229,6 +1241,12 @@ bus_context_get_loop (BusContext *context) return context->loop; } +BusCheck* +bus_context_get_check (BusContext *context) +{ + return context->check; +} + dbus_bool_t bus_context_allow_unix_user (BusContext *context, unsigned long uid) @@ -1444,6 +1462,7 @@ complain_about_message (BusContext *context, DBusConnection *proposed_recipient, dbus_bool_t requested_reply, dbus_bool_t log, + const char *privilege, DBusError *error) { DBusError stack_error = DBUS_ERROR_INIT; @@ -1473,7 +1492,8 @@ complain_about_message (BusContext *context, dbus_set_error (&stack_error, error_name, "%s, %d matched rules; type=\"%s\", sender=\"%s\" (%s) " "interface=\"%s\" member=\"%s\" error name=\"%s\" " - "requested_reply=\"%d\" destination=\"%s\" (%s)", + "requested_reply=\"%d\" destination=\"%s\" " + "privilege=\"%s\" (%s)", complaint, matched_rules, dbus_message_type_to_string (dbus_message_get_type (message)), @@ -1484,6 +1504,7 @@ complain_about_message (BusContext *context, nonnull (dbus_message_get_error_name (message), "(unset)"), requested_reply, nonnull (dbus_message_get_destination (message), DBUS_SERVICE_DBUS), + nonnull (privilege, "(n/a)"), proposed_recipient_loginfo); /* If we hit OOM while setting the error, this will syslog "out of memory" @@ -1508,14 +1529,15 @@ complain_about_message (BusContext *context, * NULL for addressed_recipient may mean the bus driver, or may mean * no destination was specified in the message (e.g. a signal). */ -dbus_bool_t -bus_context_check_security_policy (BusContext *context, - BusTransaction *transaction, - DBusConnection *sender, - DBusConnection *addressed_recipient, - DBusConnection *proposed_recipient, - DBusMessage *message, - DBusError *error) +BusResult +bus_context_check_security_policy (BusContext *context, + BusTransaction *transaction, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, + DBusMessage *message, + DBusError *error, + BusDeferredMessage **deferred_message) { const char *src, *dest; BusClientPolicy *sender_policy; @@ -1524,6 +1546,7 @@ bus_context_check_security_policy (BusContext *context, dbus_bool_t log; int type; dbus_bool_t requested_reply; + const char *privilege; type = dbus_message_get_type (message); src = dbus_message_get_sender (message); @@ -1552,7 +1575,7 @@ bus_context_check_security_policy (BusContext *context, dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Message bus will not accept messages of unknown type\n"); - return FALSE; + return BUS_RESULT_FALSE; } requested_reply = FALSE; @@ -1582,7 +1605,7 @@ bus_context_check_security_policy (BusContext *context, if (dbus_error_is_set (&error2)) { dbus_move_error (&error2, error); - return FALSE; + return BUS_RESULT_FALSE; } } } @@ -1609,7 +1632,7 @@ bus_context_check_security_policy (BusContext *context, complain_about_message (context, DBUS_ERROR_ACCESS_DENIED, "An SELinux policy prevents this sender from sending this " "message to this recipient", - 0, message, sender, proposed_recipient, FALSE, FALSE, error); + 0, message, sender, proposed_recipient, FALSE, FALSE, NULL, error); _dbus_verbose ("SELinux security check denying send to service\n"); } @@ -1644,7 +1667,7 @@ bus_context_check_security_policy (BusContext *context, { _dbus_verbose ("security check allowing %s message\n", "Hello"); - return TRUE; + return BUS_RESULT_TRUE; } else { @@ -1655,7 +1678,7 @@ bus_context_check_security_policy (BusContext *context, "Client tried to send a message other than %s without being registered", "Hello"); - return FALSE; + return BUS_RESULT_FALSE; } } } @@ -1704,20 +1727,32 @@ bus_context_check_security_policy (BusContext *context, (proposed_recipient == NULL && recipient_policy == NULL)); log = FALSE; - if (sender_policy && - !bus_client_policy_check_can_send (sender_policy, - context->registry, - requested_reply, - proposed_recipient, - message, &toggles, &log)) - { - complain_about_message (context, DBUS_ERROR_ACCESS_DENIED, - "Rejected send message", toggles, - message, sender, proposed_recipient, requested_reply, - (addressed_recipient == proposed_recipient), error); - _dbus_verbose ("security policy disallowing message due to sender policy\n"); - return FALSE; - } + if (sender_policy) { + switch (bus_client_policy_check_can_send (sender, + sender_policy, + context->registry, + requested_reply, + addressed_recipient, + proposed_recipient, + message, &toggles, &log, &privilege, + deferred_message)) + { + case BUS_RESULT_TRUE: + break; + case BUS_RESULT_FALSE: + complain_about_message (context, DBUS_ERROR_ACCESS_DENIED, + "Rejected send message", toggles, + message, sender, proposed_recipient, requested_reply, + (addressed_recipient == proposed_recipient), privilege, + error); + _dbus_verbose ("security policy disallowing message due to sender policy\n"); + return BUS_RESULT_FALSE; + break; + case BUS_RESULT_LATER: + return BUS_RESULT_LATER; + break; + } + } if (log) { @@ -1726,24 +1761,31 @@ bus_context_check_security_policy (BusContext *context, complain_about_message (context, DBUS_ERROR_ACCESS_DENIED, "Would reject message", toggles, message, sender, proposed_recipient, requested_reply, - TRUE, NULL); + TRUE, privilege, NULL); } - if (recipient_policy && - !bus_client_policy_check_can_receive (recipient_policy, - context->registry, - requested_reply, - sender, - addressed_recipient, proposed_recipient, - message, &toggles)) - { - complain_about_message (context, DBUS_ERROR_ACCESS_DENIED, - "Rejected receive message", toggles, - message, sender, proposed_recipient, requested_reply, - (addressed_recipient == proposed_recipient), error); - _dbus_verbose ("security policy disallowing message due to recipient policy\n"); - return FALSE; - } + if (recipient_policy) { + switch (bus_client_policy_check_can_receive (recipient_policy, + context->registry, + requested_reply, + sender, + addressed_recipient, proposed_recipient, + message, &toggles, &privilege, deferred_message)) + { + case BUS_RESULT_TRUE: + break; + case BUS_RESULT_FALSE: + complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, + "Rejected receive message", toggles, message, sender, + proposed_recipient, requested_reply, + (addressed_recipient == proposed_recipient), privilege, error); + _dbus_verbose( + "security policy disallowing message due to recipient policy\n"); + return BUS_RESULT_FALSE; + case BUS_RESULT_LATER: + return BUS_RESULT_LATER; + } + } /* See if limits on size have been exceeded */ if (proposed_recipient && @@ -1752,10 +1794,10 @@ bus_context_check_security_policy (BusContext *context, { complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED, "Rejected: destination has a full message queue", - 0, message, sender, proposed_recipient, requested_reply, TRUE, + 0, message, sender, proposed_recipient, requested_reply, TRUE, NULL, error); _dbus_verbose ("security policy disallowing message due to full message queue\n"); - return FALSE; + return BUS_RESULT_FALSE; } /* Record that we will allow a reply here in the future (don't @@ -1772,11 +1814,11 @@ bus_context_check_security_policy (BusContext *context, message, error)) { _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n"); - return FALSE; + return BUS_RESULT_FALSE; } _dbus_verbose ("security policy allowing message\n"); - return TRUE; + return BUS_RESULT_TRUE; } void diff --git a/bus/bus.h b/bus/bus.h index 3fab59f..4e1ef6b 100644 --- a/bus/bus.h +++ b/bus/bus.h @@ -44,6 +44,25 @@ typedef struct BusOwner BusOwner; typedef struct BusTransaction BusTransaction; typedef struct BusMatchmaker BusMatchmaker; typedef struct BusMatchRule BusMatchRule; +typedef struct BusCheck BusCheck; +typedef struct BusDeferredMessage BusDeferredMessage; +typedef struct BusCynara BusCynara; + +/** + * This uses BUS_RESULT_TRUE = 0 != TRUE intentionally, to trigger + * runtime failures where code uses a simple boolean check or + * comparison with TRUE/FALSE or returns TRUE/FALSE when it should use + * one of these enums. Such broken code unfortunately does not trigger + * compile time errors in C. + */ +typedef enum { + /** operation allowed or succeeded */ + BUS_RESULT_TRUE, + /** operation denied or failed */ + BUS_RESULT_FALSE, + /** no result yet, ask again later */ + BUS_RESULT_LATER +} BusResult; typedef struct { @@ -97,6 +116,7 @@ BusConnections* bus_context_get_connections (BusContext BusActivation* bus_context_get_activation (BusContext *context); BusMatchmaker* bus_context_get_matchmaker (BusContext *context); DBusLoop* bus_context_get_loop (BusContext *context); +BusCheck * bus_context_get_check (BusContext *context); dbus_bool_t bus_context_allow_unix_user (BusContext *context, unsigned long uid); dbus_bool_t bus_context_allow_windows_user (BusContext *context, @@ -131,13 +151,14 @@ void bus_context_log_and_set_error (BusContext const char *name, const char *msg, ...) _DBUS_GNUC_PRINTF (5, 6); -dbus_bool_t bus_context_check_security_policy (BusContext *context, - BusTransaction *transaction, - DBusConnection *sender, - DBusConnection *addressed_recipient, - DBusConnection *proposed_recipient, - DBusMessage *message, - DBusError *error); void bus_context_check_all_watches (BusContext *context); +BusResult bus_context_check_security_policy (BusContext *context, + BusTransaction *transaction, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, + DBusMessage *message, + DBusError *error, + BusDeferredMessage **deferred_message); #endif /* BUS_BUS_H */ diff --git a/bus/check.c b/bus/check.c new file mode 100644 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/connection.c b/bus/connection.c index 95e20a6..418a688 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -36,6 +36,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 @@ -116,6 +120,9 @@ typedef struct /** non-NULL if and only if this is a monitor */ DBusList *link_in_monitors; +#ifdef DBUS_ENABLE_CYNARA + char *cynara_session_id; +#endif } BusConnectionData; static dbus_bool_t bus_pending_reply_expired (BusExpireList *list, @@ -129,8 +136,8 @@ static dbus_bool_t expire_incomplete_timeout (void *data); #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot)) -static DBusLoop* -connection_get_loop (DBusConnection *connection) +DBusLoop* +bus_connection_get_loop (DBusConnection *connection) { BusConnectionData *d; @@ -354,7 +361,7 @@ add_connection_watch (DBusWatch *watch, { DBusConnection *connection = data; - return _dbus_loop_add_watch (connection_get_loop (connection), watch); + return _dbus_loop_add_watch (bus_connection_get_loop (connection), watch); } static void @@ -363,7 +370,7 @@ remove_connection_watch (DBusWatch *watch, { DBusConnection *connection = data; - _dbus_loop_remove_watch (connection_get_loop (connection), watch); + _dbus_loop_remove_watch (bus_connection_get_loop (connection), watch); } static void @@ -372,7 +379,7 @@ toggle_connection_watch (DBusWatch *watch, { DBusConnection *connection = data; - _dbus_loop_toggle_watch (connection_get_loop (connection), watch); + _dbus_loop_toggle_watch (bus_connection_get_loop (connection), watch); } static dbus_bool_t @@ -381,7 +388,7 @@ add_connection_timeout (DBusTimeout *timeout, { DBusConnection *connection = data; - return _dbus_loop_add_timeout (connection_get_loop (connection), timeout); + return _dbus_loop_add_timeout (bus_connection_get_loop (connection), timeout); } static void @@ -390,7 +397,7 @@ remove_connection_timeout (DBusTimeout *timeout, { DBusConnection *connection = data; - _dbus_loop_remove_timeout (connection_get_loop (connection), timeout); + _dbus_loop_remove_timeout (bus_connection_get_loop (connection), timeout); } static void @@ -451,6 +458,10 @@ free_connection_data (void *data) dbus_free (d->name); +#ifdef DBUS_ENABLE_CYNARA + free (d->cynara_session_id); +#endif + dbus_free (d); } @@ -1037,6 +1048,22 @@ bus_connection_get_policy (DBusConnection *connection) return d->policy; } +#ifdef DBUS_ENABLE_CYNARA +const char *bus_connection_get_cynara_session_id (DBusConnection *connection) +{ + BusConnectionData *d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + if (d->cynara_session_id == NULL) + { + unsigned long pid; + if (dbus_connection_get_unix_process_id(connection, &pid)) + d->cynara_session_id = cynara_session_from_pid(pid); + } + return d->cynara_session_id; +} +#endif + static dbus_bool_t foreach_active (BusConnections *connections, BusConnectionForeachFunction function, @@ -2300,10 +2327,14 @@ bus_transaction_send_from_driver (BusTransaction *transaction, * if we're actively capturing messages, it's nice to log that we * tried to send it and did not allow ourselves to do so. */ - if (!bus_context_check_security_policy (bus_transaction_get_context (transaction), - transaction, - NULL, connection, connection, message, &error)) - { + switch (bus_context_check_security_policy (bus_transaction_get_context (transaction), + transaction, + NULL, connection, connection, message, &error, + NULL)) + { + case BUS_RESULT_TRUE: + break; + case BUS_RESULT_FALSE: if (!bus_transaction_capture_error_reply (transaction, &error, message)) { bus_context_log (transaction->context, DBUS_SYSTEM_LOG_WARNING, @@ -2315,6 +2346,11 @@ bus_transaction_send_from_driver (BusTransaction *transaction, * message (see reasoning above) */ dbus_error_free (&error); return TRUE; + break; + case BUS_RESULT_LATER: + _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n"); + return TRUE; + break; } return bus_transaction_send (transaction, connection, message); diff --git a/bus/connection.h b/bus/connection.h index 8c68d0a..a6e5dfd 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -31,6 +31,7 @@ typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection, void *data); +DBusLoop* bus_connection_get_loop (DBusConnection *connection); BusConnections* bus_connections_new (BusContext *context); BusConnections* bus_connections_ref (BusConnections *connections); @@ -122,6 +123,9 @@ dbus_bool_t bus_connection_be_monitor (DBusConnection *connection, BusTransaction *transaction, DBusList **rules, DBusError *error); +#ifdef DBUS_ENABLE_CYNARA +const char *bus_connection_get_cynara_session_id (DBusConnection *connection); +#endif /* transaction API so we can send or not send a block of messages as a whole */ diff --git a/bus/cynara.c b/bus/cynara.c new file mode 100644 index 0000000..d659574 --- /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 +#include "cynara.h" +#include "check.h" +#include "utils.h" + +#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; + +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 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 edfa1b4..21fe886 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" @@ -64,13 +65,13 @@ send_one_message (DBusConnection *connection, DBusError *error) { DBusError stack_error = DBUS_ERROR_INIT; + BusDeferredMessage *deferred_message; + BusResult result; - if (!bus_context_check_security_policy (context, transaction, - sender, - addressed_recipient, - connection, - message, - &stack_error)) + result = bus_context_check_security_policy (context, transaction, sender, addressed_recipient, + connection, message, NULL, &deferred_message); + + if (result != BUS_RESULT_TRUE) { if (!bus_transaction_capture_error_reply (transaction, &stack_error, message)) @@ -129,6 +130,7 @@ bus_dispatch_matches (BusTransaction *transaction, BusMatchmaker *matchmaker; DBusList *link; BusContext *context; + BusDeferredMessage *deferred_message; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -144,11 +146,22 @@ bus_dispatch_matches (BusTransaction *transaction, /* First, send the message to the addressed_recipient, if there is one. */ if (addressed_recipient != NULL) { - if (!bus_context_check_security_policy (context, transaction, - sender, addressed_recipient, - addressed_recipient, - message, error)) - return FALSE; + switch (bus_context_check_security_policy (context, transaction, + sender, addressed_recipient, + addressed_recipient, + message, error, + &deferred_message)) + { + case BUS_RESULT_TRUE: + break; + case BUS_RESULT_FALSE: + return BUS_RESULT_FALSE; + case BUS_RESULT_LATER: + dbus_set_error (error, + DBUS_ERROR_ACCESS_DENIED, + "Rejecting message because time is needed to check security policy"); + return BUS_RESULT_FALSE; + } if (dbus_message_contains_unix_fds (message) && !dbus_connection_can_send_type (addressed_recipient, @@ -379,11 +392,23 @@ bus_dispatch (DBusConnection *connection, if (service_name && strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */ { - if (!bus_context_check_security_policy (context, transaction, - connection, NULL, NULL, message, &error)) + BusDeferredMessage *deferred_message; + + switch (bus_context_check_security_policy (context, transaction, + connection, NULL, NULL, message, &error, + &deferred_message)) { + case BUS_RESULT_TRUE: + break; + case BUS_RESULT_FALSE: _dbus_verbose ("Security policy rejected message\n"); goto out; + case BUS_RESULT_LATER: + dbus_set_error (&error, + DBUS_ERROR_ACCESS_DENIED, + "Rejecting message because time is needed to check security policy"); + _dbus_verbose ("Security policy needs time to check policy. Dropping message\n"); + goto out; } _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS); diff --git a/bus/policy.c b/bus/policy.c index 5af5b6b..825d754 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" @@ -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 fd66bcb..08979d2 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 1361b28..7a8e585 100644 --- a/configure.ac +++ b/configure.ac @@ -1878,6 +1878,18 @@ fi AC_SUBST([LIBSMACK_CFLAGS]) AC_SUBST([LIBSMACK_LIBS]) +#enable cynara integration +AC_ARG_ENABLE([cynara], [AS_HELP_STRING([--enable-cynara], [enable Cynara integration])], [], [enable_cynara=no]) +if test "x$enable_cynara" = xyes; then + PKG_CHECK_MODULES([CYNARA], [cynara-client-async >= 0.4.2 cynara-session >= 0.4.2], + [AC_DEFINE([DBUS_ENABLE_CYNARA], [1], [Define to enable Cynara privilege checks in dbus-daemon])], + [AC_MSG_ERROR([libcynara-client-async and cynara-session are required to enable Cynara integration])]) +fi + +AC_SUBST([CYNARA_CFLAGS]) +AC_SUBST([CYNARA_LIBS]) + + AC_CONFIG_FILES([ Doxyfile dbus/Version diff --git a/packaging/dbus.spec b/packaging/dbus.spec index e0ee7b9..40c14bc 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} -- 2.7.4