1 From 6c498a9b0f4122d1ac49d603f9968b6d85830cdb Mon Sep 17 00:00:00 2001
2 From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
3 Date: Thu, 27 Nov 2014 18:11:05 +0100
4 Subject: Integration of Cynara asynchronous security checks
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 This commit introduces basic framework for asynchronous policy
10 checks and Cynara integration code. Functions for checking security
11 policy can now return third value - BUS_RESULT_LATER denoting check
12 result unavailability. Whenever policy checker cannot decide on the
13 result of the check it is supposed to allocate DeferredMessage structure
14 that will be passed to the upper layers which can decide what should be
15 done in such situation.
16 Proper handling of such case will be implemented in subsequent commits.
17 Currently such return value results in message denial.
19 Cherry picked from 4dcfb02f17247ff9de966b62182cd2e08f301238
22 Updated for dbus 1.10.20 by Scott Murray and José Bollo
24 Change-Id: I9bcbce34577e5dc2a3cecf6233a0a2b0e43e1108
25 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
26 Signed-off-by: Scott Murray <scott.murray@konsulko.com>
28 diff --git a/bus/Makefile.am b/bus/Makefile.am
29 index 9ae3071..46afb31 100644
32 @@ -13,6 +13,7 @@ DBUS_BUS_LIBS = \
39 DBUS_LAUNCHER_LIBS = \
40 @@ -30,6 +31,7 @@ AM_CPPFLAGS = \
42 -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \
47 # if assertions are enabled, improve backtraces
48 @@ -90,6 +92,8 @@ BUS_SOURCES= \
54 config-loader-expat.c \
57 @@ -97,6 +101,8 @@ BUS_SOURCES= \
58 config-parser-common.h \
66 diff --git a/bus/activation.c b/bus/activation.c
67 index 6f009f5..f8a02eb 100644
68 --- a/bus/activation.c
69 +++ b/bus/activation.c
70 @@ -1788,14 +1788,15 @@ bus_activation_activate_service (BusActivation *activation,
72 if (auto_activation &&
74 - !bus_context_check_security_policy (activation->context,
75 + BUS_RESULT_TRUE != bus_context_check_security_policy (activation->context,
77 connection, /* sender */
78 NULL, /* addressed recipient */
79 NULL, /* proposed recipient */
86 _DBUS_ASSERT_ERROR_IS_SET (error);
87 _dbus_verbose ("activation not authorized: %s: %s\n",
88 diff --git a/bus/bus.c b/bus/bus.c
89 index 30ce4e1..237efe3 100644
95 #include "dir-watch.h"
97 #include <dbus/dbus-auth.h>
98 #include <dbus/dbus-list.h>
99 #include <dbus/dbus-hash.h>
100 @@ -67,6 +68,7 @@ struct BusContext
101 BusRegistry *registry;
103 BusMatchmaker *matchmaker;
106 DBusRLimit *initial_fd_limit;
107 unsigned int fork : 1;
108 @@ -1003,6 +1005,10 @@ bus_context_new (const DBusString *config_file,
112 + context->check = bus_check_new(context, error);
113 + if (context->check == NULL)
116 dbus_server_free_data_slot (&server_data_slot);
119 @@ -1127,6 +1133,12 @@ bus_context_unref (BusContext *context)
121 bus_context_shutdown (context);
123 + if (context->check)
125 + bus_check_unref(context->check);
126 + context->check = NULL;
129 if (context->connections)
131 bus_connections_unref (context->connections);
132 @@ -1256,6 +1268,12 @@ bus_context_get_loop (BusContext *context)
133 return context->loop;
137 +bus_context_get_check (BusContext *context)
139 + return context->check;
143 bus_context_allow_unix_user (BusContext *context,
145 @@ -1451,6 +1469,7 @@ complain_about_message (BusContext *context,
146 DBusConnection *proposed_recipient,
147 dbus_bool_t requested_reply,
149 + const char *privilege,
152 DBusError stack_error = DBUS_ERROR_INIT;
153 @@ -1480,7 +1499,8 @@ complain_about_message (BusContext *context,
154 dbus_set_error (&stack_error, error_name,
155 "%s, %d matched rules; type=\"%s\", sender=\"%s\" (%s) "
156 "interface=\"%s\" member=\"%s\" error name=\"%s\" "
157 - "requested_reply=\"%d\" destination=\"%s\" (%s)",
158 + "requested_reply=\"%d\" destination=\"%s\" (%s) "
159 + "privilege=\"%s\"",
162 dbus_message_type_to_string (dbus_message_get_type (message)),
163 @@ -1491,7 +1511,8 @@ complain_about_message (BusContext *context,
164 nonnull (dbus_message_get_error_name (message), "(unset)"),
166 nonnull (dbus_message_get_destination (message), DBUS_SERVICE_DBUS),
167 - proposed_recipient_loginfo);
168 + proposed_recipient_loginfo,
169 + nonnull (privilege, "(n/a)"));
171 /* If we hit OOM while setting the error, this will syslog "out of memory"
172 * which is itself an indication that something is seriously wrong */
173 @@ -1519,7 +1540,7 @@ complain_about_message (BusContext *context,
174 * NULL for addressed_recipient may mean the bus driver, or may mean
175 * no destination was specified in the message (e.g. a signal).
179 bus_context_check_security_policy (BusContext *context,
180 BusTransaction *transaction,
181 DBusConnection *sender,
182 @@ -1527,7 +1548,8 @@ bus_context_check_security_policy (BusContext *context,
183 DBusConnection *proposed_recipient,
184 DBusMessage *message,
185 BusActivationEntry *activation_entry,
188 + BusDeferredMessage **deferred_message)
190 const char *src, *dest;
191 BusClientPolicy *sender_policy;
192 @@ -1536,6 +1558,7 @@ bus_context_check_security_policy (BusContext *context,
195 dbus_bool_t requested_reply;
196 + const char *privilege;
198 type = dbus_message_get_type (message);
199 src = dbus_message_get_sender (message);
200 @@ -1565,7 +1588,7 @@ bus_context_check_security_policy (BusContext *context,
201 dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
202 "Message bus will not accept messages of unknown type\n");
205 + return BUS_RESULT_FALSE;
208 requested_reply = FALSE;
209 @@ -1595,7 +1618,7 @@ bus_context_check_security_policy (BusContext *context,
210 if (dbus_error_is_set (&error2))
212 dbus_move_error (&error2, error);
214 + return BUS_RESULT_FALSE;
218 @@ -1624,11 +1647,11 @@ bus_context_check_security_policy (BusContext *context,
219 complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
220 "An SELinux policy prevents this sender from sending this "
221 "message to this recipient",
222 - 0, message, sender, proposed_recipient, FALSE, FALSE, error);
223 + 0, message, sender, proposed_recipient, FALSE, FALSE, NULL, error);
224 _dbus_verbose ("SELinux security check denying send to service\n");
228 + return BUS_RESULT_FALSE;
231 /* next verify AppArmor access controls. If allowed then
232 @@ -1646,7 +1669,7 @@ bus_context_check_security_policy (BusContext *context,
233 src ? src : DBUS_SERVICE_DBUS,
237 + return BUS_RESULT_FALSE;
239 if (!bus_connection_is_active (sender))
241 @@ -1660,7 +1683,7 @@ bus_context_check_security_policy (BusContext *context,
243 _dbus_verbose ("security check allowing %s message\n",
246 + return BUS_RESULT_TRUE;
250 @@ -1671,7 +1694,7 @@ bus_context_check_security_policy (BusContext *context,
251 "Client tried to send a message other than %s without being registered",
255 + return BUS_RESULT_FALSE;
259 @@ -1720,20 +1743,29 @@ bus_context_check_security_policy (BusContext *context,
260 (proposed_recipient == NULL && recipient_policy == NULL));
263 - if (sender_policy &&
264 - !bus_client_policy_check_can_send (sender_policy,
267 - proposed_recipient,
268 - message, &toggles, &log))
270 - complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
271 - "Rejected send message", toggles,
272 - message, sender, proposed_recipient, requested_reply,
273 - (addressed_recipient == proposed_recipient), error);
274 - _dbus_verbose ("security policy disallowing message due to sender policy\n");
279 + BusResult res = bus_client_policy_check_can_send (sender,
283 + addressed_recipient,
284 + proposed_recipient,
285 + message, &toggles, &log, &privilege,
287 + if (res == BUS_RESULT_FALSE)
289 + complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
290 + "Rejected send message", toggles,
291 + message, sender, proposed_recipient, requested_reply,
292 + (addressed_recipient == proposed_recipient), privilege,
294 + _dbus_verbose ("security policy disallowing message due to sender policy\n");
295 + return BUS_RESULT_FALSE;
297 + else if (res == BUS_RESULT_LATER)
298 + return BUS_RESULT_LATER;
303 @@ -1742,23 +1774,29 @@ bus_context_check_security_policy (BusContext *context,
304 complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
305 "Would reject message", toggles,
306 message, sender, proposed_recipient, requested_reply,
308 + TRUE, privilege, NULL);
311 - if (recipient_policy &&
312 - !bus_client_policy_check_can_receive (recipient_policy,
316 - addressed_recipient, proposed_recipient,
317 - message, &toggles))
318 + if (recipient_policy)
320 - complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
321 - "Rejected receive message", toggles,
322 - message, sender, proposed_recipient, requested_reply,
323 - (addressed_recipient == proposed_recipient), error);
324 - _dbus_verbose ("security policy disallowing message due to recipient policy\n");
327 + res = bus_client_policy_check_can_receive (recipient_policy,
331 + addressed_recipient, proposed_recipient,
332 + message, &toggles, &privilege, deferred_message);
333 + if (res == BUS_RESULT_FALSE)
335 + complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected receive message",
336 + toggles, message, sender, proposed_recipient, requested_reply,
337 + (addressed_recipient == proposed_recipient), privilege, error);
339 + "security policy disallowing message due to recipient policy\n");
340 + return BUS_RESULT_FALSE;
342 + else if (res == BUS_RESULT_LATER)
343 + return BUS_RESULT_LATER;
346 /* See if limits on size have been exceeded */
347 @@ -1768,10 +1806,10 @@ bus_context_check_security_policy (BusContext *context,
349 complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
350 "Rejected: destination has a full message queue",
351 - 0, message, sender, proposed_recipient, requested_reply, TRUE,
352 + 0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
354 _dbus_verbose ("security policy disallowing message due to full message queue\n");
356 + return BUS_RESULT_FALSE;
359 /* Record that we will allow a reply here in the future (don't
360 @@ -1792,11 +1830,11 @@ bus_context_check_security_policy (BusContext *context,
363 _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
365 + return BUS_RESULT_FALSE;
368 _dbus_verbose ("security policy allowing message\n");
370 + return BUS_RESULT_TRUE;
374 diff --git a/bus/bus.h b/bus/bus.h
375 index 2e0de82..82c32c8 100644
378 @@ -45,6 +45,22 @@ typedef struct BusTransaction BusTransaction;
379 typedef struct BusMatchmaker BusMatchmaker;
380 typedef struct BusMatchRule BusMatchRule;
381 typedef struct BusActivationEntry BusActivationEntry;
382 +typedef struct BusCheck BusCheck;
383 +typedef struct BusDeferredMessage BusDeferredMessage;
384 +typedef struct BusCynara BusCynara;
387 + * BusResult is defined as a pointer to a dummy structure to allow detection of type mismatches.
388 + * The disadvantage of such solution is that now BusResult variables cannot be used in switch
390 + * Additionally, BUS_RESULT_TRUE is defined as 0 instead of 1 to help detect type mismatches
393 +typedef const struct BusResultStruct { int dummy; } *BusResult;
395 +static const BusResult BUS_RESULT_TRUE = (BusResult)0x0;
396 +static const BusResult BUS_RESULT_FALSE = (BusResult)0x1;
397 +static const BusResult BUS_RESULT_LATER = (BusResult)0x2;
401 @@ -101,6 +117,7 @@ BusConnections* bus_context_get_connections (BusContext
402 BusActivation* bus_context_get_activation (BusContext *context);
403 BusMatchmaker* bus_context_get_matchmaker (BusContext *context);
404 DBusLoop* bus_context_get_loop (BusContext *context);
405 +BusCheck * bus_context_get_check (BusContext *context);
406 dbus_bool_t bus_context_allow_unix_user (BusContext *context,
408 dbus_bool_t bus_context_allow_windows_user (BusContext *context,
409 @@ -136,14 +153,15 @@ void bus_context_log_and_set_error (BusContext
412 ...) _DBUS_GNUC_PRINTF (5, 6);
413 -dbus_bool_t bus_context_check_security_policy (BusContext *context,
414 +BusResult bus_context_check_security_policy (BusContext *context,
415 BusTransaction *transaction,
416 DBusConnection *sender,
417 DBusConnection *addressed_recipient,
418 DBusConnection *proposed_recipient,
419 DBusMessage *message,
420 BusActivationEntry *activation_entry,
423 + BusDeferredMessage **deferred_message);
424 void bus_context_check_all_watches (BusContext *context);
426 #endif /* BUS_BUS_H */
427 diff --git a/bus/check.c b/bus/check.c
429 index 0000000..5b72d31
433 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
434 +/* check.c Bus security policy runtime check
436 + * Copyright (C) 2014 Intel, Inc.
437 + * Copyright (c) 2014 Samsung Electronics, Ltd.
439 + * Licensed under the Academic Free License version 2.1
441 + * This program is free software; you can redistribute it and/or modify
442 + * it under the terms of the GNU General Public License as published by
443 + * the Free Software Foundation; either version 2 of the License, or
444 + * (at your option) any later version.
446 + * This program is distributed in the hope that it will be useful,
447 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
448 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
449 + * GNU General Public License for more details.
451 + * You should have received a copy of the GNU General Public License
452 + * along with this program; if not, write to the Free Software
453 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
459 +#include "connection.h"
460 +#include "dispatch.h"
463 +#include <dbus/dbus-connection-internal.h>
464 +#include <dbus/dbus-message-internal.h>
465 +#include <dbus/dbus-internals.h>
468 +typedef struct BusCheck
472 + BusContext *context;
476 +typedef struct BusDeferredMessage
480 + DBusMessage *message;
481 + DBusConnection *sender;
482 + DBusConnection *proposed_recipient;
483 + DBusConnection *addressed_recipient;
484 + dbus_bool_t full_dispatch;
485 + BusDeferredMessageStatus status;
486 + BusResult response;
487 + BusCheckResponseFunc response_callback;
488 +} BusDeferredMessage;
491 +bus_check_new (BusContext *context, DBusError *error)
495 + check = dbus_new(BusCheck, 1);
498 + BUS_SET_OOM(error);
502 + check->refcount = 1;
503 + check->context = context;
504 + check->cynara = bus_cynara_new(check, error);
505 + if (dbus_error_is_set(error))
515 +bus_check_ref (BusCheck *check)
517 + _dbus_assert (check->refcount > 0);
518 + check->refcount += 1;
524 +bus_check_unref (BusCheck *check)
526 + _dbus_assert (check->refcount > 0);
528 + check->refcount -= 1;
530 + if (check->refcount == 0)
532 + bus_cynara_unref(check->cynara);
538 +bus_check_get_context (BusCheck *check)
540 + return check->context;
544 +bus_check_get_cynara (BusCheck *check)
546 + return check->cynara;
550 +bus_check_privilege (BusCheck *check,
551 + DBusMessage *message,
552 + DBusConnection *sender,
553 + DBusConnection *addressed_recipient,
554 + DBusConnection *proposed_recipient,
555 + const char *privilege,
556 + BusDeferredMessageStatus check_type,
557 + BusDeferredMessage **deferred_message)
559 + BusResult result = BUS_RESULT_FALSE;
560 +#ifdef DBUS_ENABLE_CYNARA
563 + DBusConnection *connection;
565 + connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
567 + if (!dbus_connection_get_is_connected(connection))
569 + return BUS_RESULT_FALSE;
572 + /* ask policy checkers */
573 +#ifdef DBUS_ENABLE_CYNARA
574 + cynara = bus_check_get_cynara(check);
575 + result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
576 + proposed_recipient, privilege, check_type, deferred_message);
579 + if (result == BUS_RESULT_LATER && deferred_message != NULL)
581 + (*deferred_message)->status |= check_type;
586 +BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
587 + DBusConnection *sender,
588 + DBusConnection *addressed_recipient,
589 + DBusConnection *proposed_recipient,
590 + BusResult response)
592 + BusDeferredMessage *deferred_message;
594 + deferred_message = dbus_new(BusDeferredMessage, 1);
595 + if (deferred_message == NULL)
600 + deferred_message->refcount = 1;
601 + deferred_message->sender = sender != NULL ? dbus_connection_ref(sender) : NULL;
602 + deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
603 + deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
604 + deferred_message->message = dbus_message_ref(message);
605 + deferred_message->response = response;
606 + deferred_message->status = 0;
607 + deferred_message->full_dispatch = FALSE;
608 + deferred_message->response_callback = NULL;
610 + return deferred_message;
613 +BusDeferredMessage *
614 +bus_deferred_message_ref (BusDeferredMessage *deferred_message)
616 + _dbus_assert (deferred_message->refcount > 0);
617 + deferred_message->refcount += 1;
618 + return deferred_message;
622 +bus_deferred_message_unref (BusDeferredMessage *deferred_message)
624 + _dbus_assert (deferred_message->refcount > 0);
626 + deferred_message->refcount -= 1;
628 + if (deferred_message->refcount == 0)
630 + dbus_message_unref(deferred_message->message);
631 + if (deferred_message->sender != NULL)
632 + dbus_connection_unref(deferred_message->sender);
633 + if (deferred_message->addressed_recipient != NULL)
634 + dbus_connection_unref(deferred_message->addressed_recipient);
635 + if (deferred_message->proposed_recipient != NULL)
636 + dbus_connection_unref(deferred_message->proposed_recipient);
637 + dbus_free(deferred_message);
642 +bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
645 + if (deferred_message->response_callback != NULL)
647 + deferred_message->response_callback(deferred_message, result);
650 diff --git a/bus/check.h b/bus/check.h
652 index 0000000..c3fcaf9
656 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
657 +/* check.h Bus security policy runtime check
659 + * Copyright (C) 2014 Intel, Inc.
660 + * Copyright (c) 2014 Samsung Electronics, Ltd.
662 + * Licensed under the Academic Free License version 2.1
664 + * This program is free software; you can redistribute it and/or modify
665 + * it under the terms of the GNU General Public License as published by
666 + * the Free Software Foundation; either version 2 of the License, or
667 + * (at your option) any later version.
669 + * This program is distributed in the hope that it will be useful,
670 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
671 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
672 + * GNU General Public License for more details.
674 + * You should have received a copy of the GNU General Public License
675 + * along with this program; if not, write to the Free Software
676 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
687 +typedef void (*BusCheckResponseFunc) (BusDeferredMessage *message,
691 + BUS_DEFERRED_MESSAGE_CHECK_SEND = 1 << 0,
692 + BUS_DEFERRED_MESSAGE_CHECK_RECEIVE = 1 << 1,
693 + BUS_DEFERRED_MESSAGE_CHECK_OWN = 1 << 2,
694 +} BusDeferredMessageStatus;
697 +BusCheck *bus_check_new (BusContext *context,
699 +BusCheck *bus_check_ref (BusCheck *check);
700 +void bus_check_unref (BusCheck *check);
702 +BusContext *bus_check_get_context (BusCheck *check);
703 +BusCynara *bus_check_get_cynara (BusCheck *check);
704 +BusResult bus_check_privilege (BusCheck *check,
705 + DBusMessage *message,
706 + DBusConnection *sender,
707 + DBusConnection *addressed_recipient,
708 + DBusConnection *proposed_recipient,
709 + const char *privilege,
710 + BusDeferredMessageStatus check_type,
711 + BusDeferredMessage **deferred_message);
713 +BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
714 + DBusConnection *sender,
715 + DBusConnection *addressed_recipient,
716 + DBusConnection *proposed_recipient,
717 + BusResult response);
719 +BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message);
720 +void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
721 +void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
723 +#endif /* BUS_CHECK_H */
724 diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
725 index c1c4191..e2f253d 100644
726 --- a/bus/config-parser-common.c
727 +++ b/bus/config-parser-common.c
728 @@ -75,6 +75,10 @@ bus_config_parser_element_name_to_type (const char *name)
732 + else if (strcmp (name, "check") == 0)
734 + return ELEMENT_CHECK;
736 else if (strcmp (name, "servicehelper") == 0)
738 return ELEMENT_SERVICEHELPER;
739 @@ -159,6 +163,8 @@ bus_config_parser_element_type_to_name (ElementType type)
743 + case ELEMENT_CHECK:
747 case ELEMENT_PIDFILE:
748 diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
749 index 382a014..9e026d1 100644
750 --- a/bus/config-parser-common.h
751 +++ b/bus/config-parser-common.h
752 @@ -36,6 +36,7 @@ typedef enum
760 diff --git a/bus/config-parser.c b/bus/config-parser.c
761 index be27d38..b5f1dd1 100644
762 --- a/bus/config-parser.c
763 +++ b/bus/config-parser.c
764 @@ -1318,7 +1318,7 @@ append_rule_from_element (BusConfigParser *parser,
765 const char *element_name,
766 const char **attribute_names,
767 const char **attribute_values,
769 + BusPolicyRuleAccess access,
773 @@ -1360,6 +1360,7 @@ append_rule_from_element (BusConfigParser *parser,
774 const char *own_prefix;
777 + const char *privilege;
781 @@ -1390,6 +1391,7 @@ append_rule_from_element (BusConfigParser *parser,
785 + "privilege", &privilege,
789 @@ -1422,6 +1424,7 @@ append_rule_from_element (BusConfigParser *parser,
791 if (!(any_send_attribute ||
792 any_receive_attribute ||
794 own || own_prefix || user || group))
796 dbus_set_error (error, DBUS_ERROR_FAILED,
797 @@ -1438,7 +1441,30 @@ append_rule_from_element (BusConfigParser *parser,
803 + if (access == BUS_POLICY_RULE_ACCESS_CHECK)
805 + if (privilege == NULL || !*privilege)
807 + dbus_set_error (error, DBUS_ERROR_FAILED,
808 + "On element <%s>, you must specify the privilege to be checked.",
815 + if (privilege != NULL && *privilege)
817 + dbus_set_error (error, DBUS_ERROR_FAILED,
818 + "On element <%s>, privilege %s is used outside of a check rule.",
819 + element_name, privilege);
823 + privilege = NULL; /* replace (potentially) empty string with NULL pointer, it wouldn't be used anyway */
826 /* Allowed combinations of elements are:
828 * base, must be all send or all receive:
829 @@ -1589,7 +1615,7 @@ append_rule_from_element (BusConfigParser *parser,
833 - rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
834 + rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, access);
838 @@ -1694,7 +1720,7 @@ append_rule_from_element (BusConfigParser *parser,
842 - rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
843 + rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, access);
847 @@ -1726,7 +1752,7 @@ append_rule_from_element (BusConfigParser *parser,
849 else if (own || own_prefix)
851 - rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow);
852 + rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, access);
856 @@ -1752,7 +1778,7 @@ append_rule_from_element (BusConfigParser *parser,
858 if (IS_WILDCARD (user))
860 - rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
861 + rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
865 @@ -1767,7 +1793,7 @@ append_rule_from_element (BusConfigParser *parser,
867 if (_dbus_parse_unix_user_from_config (&username, &uid))
869 - rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
870 + rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
874 @@ -1784,7 +1810,7 @@ append_rule_from_element (BusConfigParser *parser,
876 if (IS_WILDCARD (group))
878 - rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
879 + rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
883 @@ -1799,7 +1825,7 @@ append_rule_from_element (BusConfigParser *parser,
885 if (_dbus_parse_unix_group_from_config (&groupname, &gid))
887 - rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
888 + rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
892 @@ -1823,6 +1849,10 @@ append_rule_from_element (BusConfigParser *parser,
893 _dbus_assert (pe != NULL);
894 _dbus_assert (pe->type == ELEMENT_POLICY);
896 + rule->privilege = _dbus_strdup (privilege);
897 + if (privilege && !rule->privilege)
900 switch (pe->d.policy.type)
903 @@ -1898,7 +1928,7 @@ start_policy_child (BusConfigParser *parser,
905 if (!append_rule_from_element (parser, element_name,
906 attribute_names, attribute_values,
908 + BUS_POLICY_RULE_ACCESS_ALLOW, error))
911 if (push_element (parser, ELEMENT_ALLOW) == NULL)
912 @@ -1913,7 +1943,7 @@ start_policy_child (BusConfigParser *parser,
914 if (!append_rule_from_element (parser, element_name,
915 attribute_names, attribute_values,
917 + BUS_POLICY_RULE_ACCESS_DENY, error))
920 if (push_element (parser, ELEMENT_DENY) == NULL)
921 @@ -1922,6 +1952,21 @@ start_policy_child (BusConfigParser *parser,
927 + else if (strcmp (element_name, "check") == 0)
929 + if (!append_rule_from_element (parser, element_name,
930 + attribute_names, attribute_values,
931 + BUS_POLICY_RULE_ACCESS_CHECK, error))
934 + if (push_element (parser, ELEMENT_CHECK) == NULL)
936 + BUS_SET_OOM (error);
943 @@ -2284,6 +2329,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
947 + case ELEMENT_CHECK:
950 case ELEMENT_KEEP_UMASK:
951 @@ -2600,6 +2646,7 @@ bus_config_parser_content (BusConfigParser *parser,
955 + case ELEMENT_CHECK:
958 case ELEMENT_KEEP_UMASK:
959 @@ -3127,6 +3174,8 @@ do_load (const DBusString *full_path,
960 dbus_error_init (&error);
962 parser = bus_config_load (full_path, TRUE, NULL, &error);
963 + if (dbus_error_is_set (&error))
964 + _dbus_verbose ("Failed to load file: %s\n", error.message);
967 _DBUS_ASSERT_ERROR_IS_SET (&error);
968 diff --git a/bus/connection.c b/bus/connection.c
969 index 53605fa..b348d42 100644
970 --- a/bus/connection.c
971 +++ b/bus/connection.c
973 #include <dbus/dbus-timeout.h>
974 #include <dbus/dbus-connection-internal.h>
975 #include <dbus/dbus-internals.h>
976 +#ifdef DBUS_ENABLE_CYNARA
978 +#include <cynara-session.h>
981 /* Trim executed commands to this length; we want to keep logs readable */
982 #define MAX_LOG_COMMAND_LEN 50
983 @@ -116,6 +120,9 @@ typedef struct
985 /** non-NULL if and only if this is a monitor */
986 DBusList *link_in_monitors;
987 +#ifdef DBUS_ENABLE_CYNARA
988 + char *cynara_session_id;
992 static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
993 @@ -129,8 +136,8 @@ static dbus_bool_t expire_incomplete_timeout (void *data);
995 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
998 -connection_get_loop (DBusConnection *connection)
1000 +bus_connection_get_loop (DBusConnection *connection)
1002 BusConnectionData *d;
1004 @@ -354,7 +361,7 @@ add_connection_watch (DBusWatch *watch,
1006 DBusConnection *connection = data;
1008 - return _dbus_loop_add_watch (connection_get_loop (connection), watch);
1009 + return _dbus_loop_add_watch (bus_connection_get_loop (connection), watch);
1013 @@ -363,7 +370,7 @@ remove_connection_watch (DBusWatch *watch,
1015 DBusConnection *connection = data;
1017 - _dbus_loop_remove_watch (connection_get_loop (connection), watch);
1018 + _dbus_loop_remove_watch (bus_connection_get_loop (connection), watch);
1022 @@ -372,7 +379,7 @@ toggle_connection_watch (DBusWatch *watch,
1024 DBusConnection *connection = data;
1026 - _dbus_loop_toggle_watch (connection_get_loop (connection), watch);
1027 + _dbus_loop_toggle_watch (bus_connection_get_loop (connection), watch);
1031 @@ -381,7 +388,7 @@ add_connection_timeout (DBusTimeout *timeout,
1033 DBusConnection *connection = data;
1035 - return _dbus_loop_add_timeout (connection_get_loop (connection), timeout);
1036 + return _dbus_loop_add_timeout (bus_connection_get_loop (connection), timeout);
1040 @@ -390,7 +397,7 @@ remove_connection_timeout (DBusTimeout *timeout,
1042 DBusConnection *connection = data;
1044 - _dbus_loop_remove_timeout (connection_get_loop (connection), timeout);
1045 + _dbus_loop_remove_timeout (bus_connection_get_loop (connection), timeout);
1049 @@ -448,6 +455,10 @@ free_connection_data (void *data)
1051 dbus_free (d->name);
1053 +#ifdef DBUS_ENABLE_CYNARA
1054 + free (d->cynara_session_id);
1060 @@ -1078,6 +1089,22 @@ bus_connection_get_policy (DBusConnection *connection)
1064 +#ifdef DBUS_ENABLE_CYNARA
1065 +const char *bus_connection_get_cynara_session_id (DBusConnection *connection)
1067 + BusConnectionData *d = BUS_CONNECTION_DATA (connection);
1068 + _dbus_assert (d != NULL);
1070 + if (d->cynara_session_id == NULL)
1072 + unsigned long pid;
1073 + if (dbus_connection_get_unix_process_id(connection, &pid))
1074 + d->cynara_session_id = cynara_session_from_pid(pid);
1076 + return d->cynara_session_id;
1081 foreach_active (BusConnections *connections,
1082 BusConnectionForeachFunction function,
1083 @@ -2333,6 +2360,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
1084 DBusMessage *message)
1086 DBusError error = DBUS_ERROR_INIT;
1089 /* We have to set the sender to the driver, and have
1090 * to check security policy since it was not done in
1091 @@ -2370,10 +2398,11 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
1092 * if we're actively capturing messages, it's nice to log that we
1093 * tried to send it and did not allow ourselves to do so.
1095 - if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
1097 - NULL, connection, connection,
1098 - message, NULL, &error))
1099 + res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
1101 + NULL, connection, connection, message, NULL,
1103 + if (res == BUS_RESULT_FALSE)
1105 if (!bus_transaction_capture_error_reply (transaction, connection,
1107 @@ -2388,6 +2417,12 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
1108 dbus_error_free (&error);
1111 + else if (res == BUS_RESULT_LATER)
1113 + _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
1114 + dbus_error_free (&error);
1118 return bus_transaction_send (transaction, connection, message);
1120 diff --git a/bus/connection.h b/bus/connection.h
1121 index 9e253ae..71078ea 100644
1122 --- a/bus/connection.h
1123 +++ b/bus/connection.h
1125 typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection,
1128 +DBusLoop* bus_connection_get_loop (DBusConnection *connection);
1130 BusConnections* bus_connections_new (BusContext *context);
1131 BusConnections* bus_connections_ref (BusConnections *connections);
1132 @@ -124,6 +125,9 @@ dbus_bool_t bus_connection_be_monitor (DBusConnection *connection,
1133 BusTransaction *transaction,
1136 +#ifdef DBUS_ENABLE_CYNARA
1137 +const char *bus_connection_get_cynara_session_id (DBusConnection *connection);
1140 /* transaction API so we can send or not send a block of messages as a whole */
1142 diff --git a/bus/cynara.c b/bus/cynara.c
1143 new file mode 100644
1144 index 0000000..57a4c45
1148 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
1149 +/* cynara.c Cynara runtime privilege checking
1151 + * Copyright (c) 2014 Samsung Electronics, Ltd.
1153 + * Licensed under the Academic Free License version 2.1
1155 + * This program is free software; you can redistribute it and/or modify
1156 + * it under the terms of the GNU General Public License as published by
1157 + * the Free Software Foundation; either version 2 of the License, or
1158 + * (at your option) any later version.
1160 + * This program is distributed in the hope that it will be useful,
1161 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1162 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1163 + * GNU General Public License for more details.
1165 + * You should have received a copy of the GNU General Public License
1166 + * along with this program; if not, write to the Free Software
1167 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1171 +#include <config.h>
1172 +#include "cynara.h"
1178 +#include <dbus/dbus.h>
1179 +#include <dbus/dbus-watch.h>
1180 +#include <dbus/dbus-connection-internal.h>
1181 +#include <bus/connection.h>
1182 +#ifdef DBUS_ENABLE_CYNARA
1183 +#include <cynara-client-async.h>
1187 +#ifdef DBUS_ENABLE_CYNARA
1188 +typedef struct BusCynara
1192 + BusContext *context;
1194 + cynara_async *cynara;
1195 + DBusWatch *cynara_watch;
1198 +#define USE_CYNARA_CACHE 1
1199 +#ifdef USE_CYNARA_CACHE
1200 +#define CYNARA_CACHE_SIZE 7000
1203 +static dbus_bool_t bus_cynara_watch_callback(DBusWatch *watch,
1204 + unsigned int flags,
1207 +static void status_callback(int old_fd,
1209 + cynara_async_status status,
1210 + void *user_status_data);
1211 +static void bus_cynara_check_response_callback (cynara_check_id check_id,
1212 + cynara_async_call_cause cause,
1214 + void *user_response_data);
1219 +bus_cynara_new(BusCheck *check, DBusError *error)
1221 +#ifdef DBUS_ENABLE_CYNARA
1222 + BusContext *context;
1223 + BusCynara *cynara;
1224 + cynara_async_configuration *conf = NULL;
1227 + cynara = dbus_new(BusCynara, 1);
1228 + if (cynara == NULL)
1230 + BUS_SET_OOM(error);
1234 + context = bus_check_get_context(check);
1236 + cynara->refcount = 1;
1237 + cynara->check = check;
1238 + cynara->context = context;
1239 + cynara->cynara_watch = NULL;
1241 + ret = cynara_async_configuration_create(&conf);
1242 + if (ret != CYNARA_API_SUCCESS)
1244 + dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to create Cynara configuration");
1248 +#ifdef CYNARA_CACHE_SIZE
1249 + ret = cynara_async_configuration_set_cache_size(conf, CYNARA_CACHE_SIZE);
1250 + if (ret != CYNARA_API_SUCCESS)
1252 + dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to Cynara cache size");
1257 + ret = cynara_async_initialize(&cynara->cynara, conf, &status_callback, cynara);
1258 + if (ret != CYNARA_API_SUCCESS)
1260 + dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to initialize Cynara client");
1265 + cynara_async_configuration_destroy(conf);
1266 + if (ret != CYNARA_API_SUCCESS)
1268 + dbus_free(cynara);
1279 +bus_cynara_ref (BusCynara *cynara)
1281 +#ifdef DBUS_ENABLE_CYNARA
1282 + _dbus_assert (cynara->refcount > 0);
1283 + cynara->refcount += 1;
1292 +bus_cynara_unref (BusCynara *cynara)
1294 +#ifdef DBUS_ENABLE_CYNARA
1295 + _dbus_assert (cynara->refcount > 0);
1297 + cynara->refcount -= 1;
1299 + if (cynara->refcount == 0)
1301 + cynara_async_finish(cynara->cynara);
1302 + dbus_free(cynara);
1308 +bus_cynara_check_privilege (BusCynara *cynara,
1309 + DBusMessage *message,
1310 + DBusConnection *sender,
1311 + DBusConnection *addressed_recipient,
1312 + DBusConnection *proposed_recipient,
1313 + const char *privilege,
1314 + BusDeferredMessageStatus check_type,
1315 + BusDeferredMessage **deferred_message_param)
1317 +#ifdef DBUS_ENABLE_CYNARA
1319 + unsigned long uid;
1321 + const char *session_id;
1323 + cynara_check_id check_id;
1324 + DBusConnection *connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
1325 + BusDeferredMessage *deferred_message;
1328 + _dbus_assert(connection != NULL);
1330 + if (dbus_connection_get_unix_user(connection, &uid) == FALSE)
1331 + return BUS_RESULT_FALSE;
1333 + if (_dbus_connection_get_linux_security_label(connection, &label) == FALSE || label == NULL)
1335 + _dbus_warn("Failed to obtain security label for connection\n");
1336 + return BUS_RESULT_FALSE;
1339 + session_id = bus_connection_get_cynara_session_id (connection);
1340 + if (session_id == NULL)
1342 + ret = BUS_RESULT_FALSE;
1346 + snprintf(user, sizeof(user), "%lu", uid);
1348 +#if USE_CYNARA_CACHE
1349 + result = cynara_async_check_cache(cynara->cynara, label, session_id, user, privilege);
1351 + result = CYNARA_API_CACHE_MISS;
1356 + case CYNARA_API_ACCESS_ALLOWED:
1357 + _dbus_verbose("Cynara: got ALLOWED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
1358 + label, session_id, user, privilege);
1359 + ret = BUS_RESULT_TRUE;
1362 + case CYNARA_API_ACCESS_DENIED:
1363 + _dbus_verbose("Cynara: got DENIED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
1364 + label, session_id, user, privilege);
1365 + ret = BUS_RESULT_FALSE;
1368 + case CYNARA_API_CACHE_MISS:
1369 + deferred_message = bus_deferred_message_new(message, sender, addressed_recipient,
1370 + proposed_recipient, BUS_RESULT_LATER);
1371 + if (deferred_message == NULL)
1373 + _dbus_verbose("Failed to allocate memory for deferred message\n");
1374 + ret = BUS_RESULT_FALSE;
1378 + /* callback is supposed to unref deferred_message*/
1379 + result = cynara_async_create_request(cynara->cynara, label, session_id, user, privilege, &check_id,
1380 + &bus_cynara_check_response_callback, deferred_message);
1381 + if (result == CYNARA_API_SUCCESS)
1383 + _dbus_verbose("Created Cynara request: client=%s session_id=%s user=%s privilege=%s check_id=%u "
1384 + "deferred_message=%p\n", label, session_id, user, privilege, (unsigned int)check_id, deferred_message);
1385 + if (deferred_message_param != NULL)
1386 + *deferred_message_param = deferred_message;
1387 + ret = BUS_RESULT_LATER;
1391 + _dbus_verbose("Error on cynara request create: %i\n", result);
1392 + bus_deferred_message_unref(deferred_message);
1393 + ret = BUS_RESULT_FALSE;
1397 + _dbus_verbose("Error when accessing Cynara cache: %i\n", result);
1398 + ret = BUS_RESULT_FALSE;
1405 + return BUS_RESULT_FALSE;
1411 +#ifdef DBUS_ENABLE_CYNARA
1413 +status_callback(int old_fd, int new_fd, cynara_async_status status,
1414 + void *user_status_data)
1416 + BusCynara *cynara = (BusCynara *)user_status_data;
1417 + DBusLoop *loop = bus_context_get_loop(cynara->context);
1419 + if (cynara->cynara_watch != NULL)
1421 + _dbus_loop_remove_watch(loop, cynara->cynara_watch);
1422 + _dbus_watch_invalidate(cynara->cynara_watch);
1423 + _dbus_watch_unref(cynara->cynara_watch);
1424 + cynara->cynara_watch = NULL;
1429 + unsigned int flags;
1434 + case CYNARA_STATUS_FOR_READ:
1435 + flags = DBUS_WATCH_READABLE;
1437 + case CYNARA_STATUS_FOR_RW:
1438 + flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
1441 + /* Cynara passed unknown status - warn and add RW watch */
1442 + _dbus_verbose("Cynara passed unknown status value: 0x%08X\n", (unsigned int)status);
1443 + flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
1447 + watch = _dbus_watch_new(new_fd, flags, TRUE, &bus_cynara_watch_callback, cynara, NULL);
1448 + if (watch != NULL)
1450 + if (_dbus_loop_add_watch(loop, watch) == TRUE)
1452 + cynara->cynara_watch = watch;
1456 + _dbus_watch_invalidate(watch);
1457 + _dbus_watch_unref(watch);
1460 + /* It seems like not much can be done at this point. Cynara events won't be processed
1461 + * until next Cynara function call triggering status callback */
1462 + _dbus_verbose("Failed to add dbus watch\n");
1467 +bus_cynara_watch_callback(DBusWatch *watch,
1468 + unsigned int flags,
1471 + BusCynara *cynara = (BusCynara *)data;
1472 + int result = cynara_async_process(cynara->cynara);
1473 + if (result != CYNARA_API_SUCCESS)
1474 + _dbus_verbose("cynara_async_process returned %d\n", result);
1476 + return result != CYNARA_API_OUT_OF_MEMORY ? TRUE : FALSE;
1479 +static inline const char *
1480 +call_cause_to_string(cynara_async_call_cause cause)
1484 + case CYNARA_CALL_CAUSE_ANSWER:
1486 + case CYNARA_CALL_CAUSE_CANCEL:
1488 + case CYNARA_CALL_CAUSE_FINISH:
1490 + case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE:
1491 + return "SERVICE NOT AVAILABLE";
1498 +bus_cynara_check_response_callback (cynara_check_id check_id,
1499 + cynara_async_call_cause cause,
1501 + void *user_response_data)
1503 + BusDeferredMessage *deferred_message = user_response_data;
1506 + _dbus_verbose("Cynara callback: check_id=%u, cause=%s response=%i response_data=%p\n",
1507 + (unsigned int)check_id, call_cause_to_string(cause), response, user_response_data);
1509 + if (deferred_message == NULL)
1512 + if (cause == CYNARA_CALL_CAUSE_ANSWER && response == CYNARA_API_ACCESS_ALLOWED)
1513 + result = BUS_RESULT_TRUE;
1515 + result = BUS_RESULT_FALSE;
1517 + bus_deferred_message_response_received(deferred_message, result);
1518 + bus_deferred_message_unref(deferred_message);
1521 +#endif /* DBUS_ENABLE_CYNARA */
1522 diff --git a/bus/cynara.h b/bus/cynara.h
1523 new file mode 100644
1524 index 0000000..c4728bb
1528 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
1529 +/* cynara.h Cynara runtime privilege checking
1531 + * Copyright (c) 2014 Samsung Electronics, Ltd.
1533 + * Licensed under the Academic Free License version 2.1
1535 + * This program is free software; you can redistribute it and/or modify
1536 + * it under the terms of the GNU General Public License as published by
1537 + * the Free Software Foundation; either version 2 of the License, or
1538 + * (at your option) any later version.
1540 + * This program is distributed in the hope that it will be useful,
1541 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1542 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1543 + * GNU General Public License for more details.
1545 + * You should have received a copy of the GNU General Public License
1546 + * along with this program; if not, write to the Free Software
1547 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1554 +BusCynara *bus_cynara_new (BusCheck *check, DBusError *error);
1555 +BusCynara *bus_cynara_ref (BusCynara *cynara);
1556 +void bus_cynara_unref (BusCynara *cynara);
1557 +BusResult bus_cynara_check_privilege (BusCynara *cynara,
1558 + DBusMessage *message,
1559 + DBusConnection *sender,
1560 + DBusConnection *addressed_recipient,
1561 + DBusConnection *proposed_recipient,
1562 + const char *privilege,
1563 + BusDeferredMessageStatus check_type,
1564 + BusDeferredMessage **deferred_message);
1565 diff --git a/bus/dispatch.c b/bus/dispatch.c
1566 index 19228be..d3867f7 100644
1567 --- a/bus/dispatch.c
1568 +++ b/bus/dispatch.c
1572 #include "dispatch.h"
1574 #include "connection.h"
1576 #include "services.h"
1577 @@ -64,14 +65,18 @@ send_one_message (DBusConnection *connection,
1580 DBusError stack_error = DBUS_ERROR_INIT;
1581 + BusDeferredMessage *deferred_message;
1584 - if (!bus_context_check_security_policy (context, transaction,
1585 + result = bus_context_check_security_policy (context, transaction,
1587 addressed_recipient,
1593 + &deferred_message);
1594 + if (result != BUS_RESULT_TRUE)
1596 if (!bus_transaction_capture_error_reply (transaction, sender,
1597 &stack_error, message))
1598 @@ -130,6 +135,8 @@ bus_dispatch_matches (BusTransaction *transaction,
1599 BusMatchmaker *matchmaker;
1601 BusContext *context;
1602 + BusDeferredMessage *deferred_message;
1605 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1607 @@ -145,11 +152,20 @@ bus_dispatch_matches (BusTransaction *transaction,
1608 /* First, send the message to the addressed_recipient, if there is one. */
1609 if (addressed_recipient != NULL)
1611 - if (!bus_context_check_security_policy (context, transaction,
1612 - sender, addressed_recipient,
1613 - addressed_recipient,
1614 - message, NULL, error))
1615 + res = bus_context_check_security_policy (context, transaction,
1616 + sender, addressed_recipient,
1617 + addressed_recipient,
1618 + message, NULL, error,
1619 + &deferred_message);
1620 + if (res == BUS_RESULT_FALSE)
1622 + else if (res == BUS_RESULT_LATER)
1624 + dbus_set_error (error,
1625 + DBUS_ERROR_ACCESS_DENIED,
1626 + "Rejecting message because time is needed to check security policy");
1630 if (dbus_message_contains_unix_fds (message) &&
1631 !dbus_connection_can_send_type (addressed_recipient,
1632 @@ -374,19 +390,31 @@ bus_dispatch (DBusConnection *connection,
1634 strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
1636 + BusDeferredMessage *deferred_message;
1639 if (!bus_transaction_capture (transaction, connection, NULL, message))
1641 BUS_SET_OOM (&error);
1645 - if (!bus_context_check_security_policy (context, transaction,
1646 - connection, NULL, NULL, message,
1648 + res = bus_context_check_security_policy (context, transaction,
1649 + connection, NULL, NULL, message, NULL,
1650 + &error, &deferred_message);
1651 + if (res == BUS_RESULT_FALSE)
1653 _dbus_verbose ("Security policy rejected message\n");
1656 + else if (res == BUS_RESULT_LATER)
1658 + dbus_set_error (&error,
1659 + DBUS_ERROR_ACCESS_DENIED,
1660 + "Rejecting message because time is needed to check security policy");
1661 + _dbus_verbose ("Security policy needs time to check policy. Dropping message\n");
1665 _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS);
1666 if (!bus_driver_handle_message (connection, transaction, message, &error))
1667 diff --git a/bus/policy.c b/bus/policy.c
1668 index a37be80..7ee1ce5 100644
1677 #include "services.h"
1682 bus_policy_rule_new (BusPolicyRuleType type,
1683 - dbus_bool_t allow)
1684 + BusPolicyRuleAccess access)
1686 BusPolicyRule *rule;
1688 @@ -43,7 +44,7 @@ bus_policy_rule_new (BusPolicyRuleType type,
1692 - rule->allow = allow;
1693 + rule->access = access;
1697 @@ -55,18 +56,19 @@ bus_policy_rule_new (BusPolicyRuleType type,
1699 case BUS_POLICY_RULE_SEND:
1700 rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
1702 /* allow rules default to TRUE (only requested replies allowed)
1703 + * check rules default to TRUE (only requested replies are checked)
1704 * deny rules default to FALSE (only unrequested replies denied)
1706 - rule->d.send.requested_reply = rule->allow;
1707 + rule->d.send.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
1709 case BUS_POLICY_RULE_RECEIVE:
1710 rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
1711 /* allow rules default to TRUE (only requested replies allowed)
1712 + * check rules default to TRUE (only requested replies are checked)
1713 * deny rules default to FALSE (only unrequested replies denied)
1715 - rule->d.receive.requested_reply = rule->allow;
1716 + rule->d.receive.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
1718 case BUS_POLICY_RULE_OWN:
1720 @@ -122,7 +124,8 @@ bus_policy_rule_unref (BusPolicyRule *rule)
1722 _dbus_assert_not_reached ("invalid rule");
1726 + dbus_free (rule->privilege);
1730 @@ -435,7 +438,10 @@ list_allows_user (dbus_bool_t def,
1734 - allowed = rule->allow;
1735 + /* We don't intend to support <check user="..." /> and <check group="..." />
1736 + rules. They are treated like deny.
1738 + allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
1742 @@ -873,18 +879,23 @@ bus_client_policy_append_rule (BusClientPolicy *policy,
1747 -bus_client_policy_check_can_send (BusClientPolicy *policy,
1748 - BusRegistry *registry,
1749 - dbus_bool_t requested_reply,
1750 - DBusConnection *receiver,
1751 - DBusMessage *message,
1752 - dbus_int32_t *toggles,
1755 +bus_client_policy_check_can_send (DBusConnection *sender,
1756 + BusClientPolicy *policy,
1757 + BusRegistry *registry,
1758 + dbus_bool_t requested_reply,
1759 + DBusConnection *addressed_recipient,
1760 + DBusConnection *receiver,
1761 + DBusMessage *message,
1762 + dbus_int32_t *toggles,
1764 + const char **privilege_param,
1765 + BusDeferredMessage **deferred_message)
1768 - dbus_bool_t allowed;
1771 + const char *privilege;
1773 /* policy->rules is in the order the rules appeared
1774 * in the config file, i.e. last rule that applies wins
1776 @@ -892,7 +903,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1777 _dbus_verbose (" (policy) checking send rules\n");
1781 + result = BUS_RESULT_FALSE;
1782 link = _dbus_list_get_first_link (&policy->rules);
1783 while (link != NULL)
1785 @@ -923,13 +934,14 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1786 /* If it's a reply, the requested_reply flag kicks in */
1787 if (dbus_message_get_reply_serial (message) != 0)
1789 - /* for allow, requested_reply=true means the rule applies
1790 - * only when reply was requested. requested_reply=false means
1792 + /* for allow or check requested_reply=true means the rule applies
1793 + * only when reply was requested. requested_reply=false means the
1794 + * rule always applies
1796 - if (!requested_reply && rule->allow && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
1797 + if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
1799 - _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
1800 + _dbus_verbose (" (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
1801 + rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
1805 @@ -937,7 +949,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1806 * when the reply was not requested. requested_reply=true means the
1807 * rule always applies.
1809 - if (requested_reply && !rule->allow && !rule->d.send.requested_reply)
1810 + if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.send.requested_reply)
1812 _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n");
1814 @@ -960,13 +972,15 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1815 /* The interface is optional in messages. For allow rules, if the message
1816 * has no interface we want to skip the rule (and thus not allow);
1817 * for deny rules, if the message has no interface we want to use the
1818 - * rule (and thus deny).
1819 + * rule (and thus deny). Check rules are meant to be used like allow
1820 + * rules (they can grant access, but not remove it), so we treat it like
1823 dbus_bool_t no_interface;
1825 no_interface = dbus_message_get_interface (message) == NULL;
1827 - if ((no_interface && rule->allow) ||
1828 + if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
1830 strcmp (dbus_message_get_interface (message),
1831 rule->d.send.interface) != 0))
1832 @@ -1079,33 +1093,63 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1836 - allowed = rule->allow;
1837 + switch (rule->access)
1839 + case BUS_POLICY_RULE_ACCESS_ALLOW:
1840 + result = BUS_RESULT_TRUE;
1842 + case BUS_POLICY_RULE_ACCESS_DENY:
1843 + result = BUS_RESULT_FALSE;
1845 + case BUS_POLICY_RULE_ACCESS_CHECK:
1846 + result = BUS_RESULT_LATER;
1847 + privilege = rule->privilege;
1851 *log = rule->d.send.log;
1854 - _dbus_verbose (" (policy) used rule, allow now = %d\n",
1856 + _dbus_verbose (" (policy) used rule, result now = %d\n",
1857 + (int)(intptr_t)result);
1861 + if (result == BUS_RESULT_LATER)
1863 + BusContext *context = bus_connection_get_context(sender);
1864 + BusCheck *check = bus_context_get_check(context);
1866 + result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
1867 + privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
1872 + if (privilege_param != NULL)
1873 + *privilege_param = privilege;
1878 /* See docs on what the args mean on bus_context_check_security_policy()
1882 -bus_client_policy_check_can_receive (BusClientPolicy *policy,
1883 - BusRegistry *registry,
1884 - dbus_bool_t requested_reply,
1885 - DBusConnection *sender,
1886 - DBusConnection *addressed_recipient,
1887 - DBusConnection *proposed_recipient,
1888 - DBusMessage *message,
1889 - dbus_int32_t *toggles)
1891 +bus_client_policy_check_can_receive (BusClientPolicy *policy,
1892 + BusRegistry *registry,
1893 + dbus_bool_t requested_reply,
1894 + DBusConnection *sender,
1895 + DBusConnection *addressed_recipient,
1896 + DBusConnection *proposed_recipient,
1897 + DBusMessage *message,
1898 + dbus_int32_t *toggles,
1899 + const char **privilege_param,
1900 + BusDeferredMessage **deferred_message)
1903 - dbus_bool_t allowed;
1904 dbus_bool_t eavesdropping;
1906 + const char *privilege;
1909 addressed_recipient != proposed_recipient &&
1910 @@ -1118,7 +1162,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1911 _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
1915 + result = BUS_RESULT_FALSE;
1916 link = _dbus_list_get_first_link (&policy->rules);
1917 while (link != NULL)
1919 @@ -1141,19 +1185,21 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1923 - /* for allow, eavesdrop=false means the rule doesn't apply when
1924 - * eavesdropping. eavesdrop=true means always allow.
1926 + /* for allow or check, eavesdrop=false means the rule doesn't apply when
1927 + * eavesdropping. eavesdrop=true means the rule always applies
1929 - if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop)
1930 + if (eavesdropping && rule->access != BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.eavesdrop)
1932 - _dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n");
1933 + _dbus_verbose (" (policy) skipping %s rule since it doesn't apply to eavesdropping\n",
1934 + rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
1938 /* for deny, eavesdrop=true means the rule applies only when
1939 * eavesdropping; eavesdrop=false means always deny.
1941 - if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop)
1942 + if (!eavesdropping && rule->access == BUS_POLICY_RULE_ACCESS_DENY && rule->d.receive.eavesdrop)
1944 _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n");
1946 @@ -1162,13 +1208,14 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1947 /* If it's a reply, the requested_reply flag kicks in */
1948 if (dbus_message_get_reply_serial (message) != 0)
1950 - /* for allow, requested_reply=true means the rule applies
1951 - * only when reply was requested. requested_reply=false means
1953 + /* for allow or check requested_reply=true means the rule applies
1954 + * only when reply was requested. requested_reply=false means the
1955 + * rule always applies
1957 - if (!requested_reply && rule->allow && rule->d.receive.requested_reply && !rule->d.receive.eavesdrop)
1958 + if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
1960 - _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
1961 + _dbus_verbose (" (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
1962 + rule->access == BUS_POLICY_RULE_ACCESS_DENY ? "allow" : "deny");
1966 @@ -1176,7 +1223,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1967 * when the reply was not requested. requested_reply=true means the
1968 * rule always applies.
1970 - if (requested_reply && !rule->allow && !rule->d.receive.requested_reply)
1971 + if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.requested_reply)
1973 _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n");
1975 @@ -1199,13 +1246,13 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1976 /* The interface is optional in messages. For allow rules, if the message
1977 * has no interface we want to skip the rule (and thus not allow);
1978 * for deny rules, if the message has no interface we want to use the
1979 - * rule (and thus deny).
1980 + * rule (and thus deny). Check rules are treated like allow rules.
1982 dbus_bool_t no_interface;
1984 no_interface = dbus_message_get_interface (message) == NULL;
1986 - if ((no_interface && rule->allow) ||
1987 + if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
1989 strcmp (dbus_message_get_interface (message),
1990 rule->d.receive.interface) != 0))
1991 @@ -1295,14 +1342,42 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1995 - allowed = rule->allow;
1996 + switch (rule->access)
1998 + case BUS_POLICY_RULE_ACCESS_ALLOW:
1999 + result = BUS_RESULT_TRUE;
2001 + case BUS_POLICY_RULE_ACCESS_DENY:
2002 + result = BUS_RESULT_FALSE;
2004 + case BUS_POLICY_RULE_ACCESS_CHECK:
2005 + result = BUS_RESULT_LATER;
2006 + privilege = rule->privilege;
2012 - _dbus_verbose (" (policy) used rule, allow now = %d\n",
2014 + _dbus_verbose (" (policy) used rule, result now = %d\n",
2015 + (int)(intptr_t)result);
2020 + if (result == BUS_RESULT_LATER)
2022 + BusContext *context = bus_connection_get_context(proposed_recipient);
2023 + BusCheck *check = bus_context_get_check(context);
2025 + result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
2026 + privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
2031 + if (privilege_param != NULL)
2032 + *privilege_param = privilege;
2038 @@ -1354,7 +1429,7 @@ bus_rules_check_can_own (DBusList *rules,
2042 - allowed = rule->allow;
2043 + allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
2047 diff --git a/bus/policy.h b/bus/policy.h
2048 index ec43ffa..f839d23 100644
2051 @@ -46,6 +46,14 @@ typedef enum
2052 BUS_POLICY_TRISTATE_TRUE
2053 } BusPolicyTristate;
2057 + BUS_POLICY_RULE_ACCESS_DENY,
2058 + BUS_POLICY_RULE_ACCESS_ALLOW,
2059 + /** runtime check resulting in allow or deny */
2060 + BUS_POLICY_RULE_ACCESS_CHECK
2061 +} BusPolicyRuleAccess;
2063 /** determines whether the rule affects a connection, or some global item */
2064 #define BUS_POLICY_RULE_IS_PER_CLIENT(rule) (!((rule)->type == BUS_POLICY_RULE_USER || \
2065 (rule)->type == BUS_POLICY_RULE_GROUP))
2066 @@ -56,8 +64,9 @@ struct BusPolicyRule
2068 BusPolicyRuleType type;
2070 - unsigned int allow : 1; /**< #TRUE if this allows, #FALSE if it denies */
2072 + unsigned int access : 2; /**< BusPolicyRuleAccess */
2073 + char *privilege; /**< for BUS_POLICY_RULE_ACCESS_CHECK */
2078 @@ -118,7 +127,7 @@ struct BusPolicyRule
2081 BusPolicyRule* bus_policy_rule_new (BusPolicyRuleType type,
2082 - dbus_bool_t allow);
2083 + BusPolicyRuleAccess access);
2084 BusPolicyRule* bus_policy_rule_ref (BusPolicyRule *rule);
2085 void bus_policy_rule_unref (BusPolicyRule *rule);
2087 @@ -152,21 +161,27 @@ dbus_bool_t bus_policy_merge (BusPolicy *policy,
2088 BusClientPolicy* bus_client_policy_new (void);
2089 BusClientPolicy* bus_client_policy_ref (BusClientPolicy *policy);
2090 void bus_client_policy_unref (BusClientPolicy *policy);
2091 -dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy,
2092 +BusResult bus_client_policy_check_can_send (DBusConnection *sender,
2093 + BusClientPolicy *policy,
2094 BusRegistry *registry,
2095 dbus_bool_t requested_reply,
2096 + DBusConnection *addressed_recipient,
2097 DBusConnection *receiver,
2098 DBusMessage *message,
2099 dbus_int32_t *toggles,
2100 - dbus_bool_t *log);
2101 -dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy,
2103 + const char **privilege_param,
2104 + BusDeferredMessage **deferred_message);
2105 +BusResult bus_client_policy_check_can_receive (BusClientPolicy *policy,
2106 BusRegistry *registry,
2107 dbus_bool_t requested_reply,
2108 DBusConnection *sender,
2109 DBusConnection *addressed_recipient,
2110 DBusConnection *proposed_recipient,
2111 DBusMessage *message,
2112 - dbus_int32_t *toggles);
2113 + dbus_int32_t *toggles,
2114 + const char **privilege_param,
2115 + BusDeferredMessage **deferred_message);
2116 dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy,
2117 const DBusString *service_name);
2118 dbus_bool_t bus_client_policy_append_rule (BusClientPolicy *policy,
2119 diff --git a/configure.ac b/configure.ac
2120 index 81028ba..f21d1b2 100644
2123 @@ -1770,6 +1770,17 @@ AC_ARG_ENABLE([user-session],
2124 AM_CONDITIONAL([DBUS_ENABLE_USER_SESSION],
2125 [test "x$enable_user_session" = xyes])
2127 +#enable cynara integration
2128 +AC_ARG_ENABLE([cynara], [AS_HELP_STRING([--enable-cynara], [enable Cynara integration])], [], [enable_cynara=no])
2129 +if test "x$enable_cynara" = xyes; then
2130 + PKG_CHECK_MODULES([CYNARA], [cynara-client-async >= 0.6.0 cynara-session >= 0.6.0],
2131 + [AC_DEFINE([DBUS_ENABLE_CYNARA], [1], [Define to enable Cynara privilege checks in dbus-daemon])],
2132 + [AC_MSG_ERROR([libcynara-client-async and cynara-session are required to enable Cynara integration])])
2135 +AC_SUBST([CYNARA_CFLAGS])
2136 +AC_SUBST([CYNARA_LIBS])
2141 @@ -1852,6 +1863,7 @@ echo "
2142 Building bus stats API: ${enable_stats}
2143 Building SELinux support: ${have_selinux}
2144 Building AppArmor support: ${have_apparmor}
2145 + Building Cynara support: ${enable_cynara}
2146 Building inotify support: ${have_inotify}
2147 Building kqueue support: ${have_kqueue}
2148 Building systemd support: ${have_systemd}
2149 diff --git a/test/Makefile.am b/test/Makefile.am
2150 index 6a6e1a3..ce84dbc 100644
2151 --- a/test/Makefile.am
2152 +++ b/test/Makefile.am
2153 @@ -439,6 +439,7 @@ in_data = \
2154 data/valid-config-files/debug-allow-all.conf.in \
2155 data/valid-config-files/finite-timeout.conf.in \
2156 data/valid-config-files/forbidding.conf.in \
2157 + data/valid-config-files/debug-check-some.conf.in \
2158 data/valid-config-files/incoming-limit.conf.in \
2159 data/valid-config-files/max-completed-connections.conf.in \
2160 data/valid-config-files/max-connections-per-user.conf.in \
2161 diff --git a/test/data/invalid-config-files/badcheck-1.conf b/test/data/invalid-config-files/badcheck-1.conf
2162 new file mode 100644
2163 index 0000000..fad9f50
2165 +++ b/test/data/invalid-config-files/badcheck-1.conf
2167 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2168 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2170 + <user>mybususer</user>
2171 + <listen>unix:path=/foo/bar</listen>
2172 + <policy context="default">
2173 + <allow privilege="foo" send_destination="*"/> <!-- extra privilege="foo" -->
2176 diff --git a/test/data/invalid-config-files/badcheck-2.conf b/test/data/invalid-config-files/badcheck-2.conf
2177 new file mode 100644
2178 index 0000000..63c7ef2
2180 +++ b/test/data/invalid-config-files/badcheck-2.conf
2182 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2183 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2185 + <user>mybususer</user>
2186 + <listen>unix:path=/foo/bar</listen>
2187 + <policy context="default">
2188 + <check send_destination="*"/> <!-- missing privilege="foo" -->
2191 diff --git a/test/data/valid-config-files/check-1.conf b/test/data/valid-config-files/check-1.conf
2192 new file mode 100644
2193 index 0000000..ad71473
2195 +++ b/test/data/valid-config-files/check-1.conf
2197 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2198 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2200 + <user>mybususer</user>
2201 + <listen>unix:path=/foo/bar</listen>
2202 + <policy context="default">
2203 + <check privilege="foo" send_destination="*"/>
2206 diff --git a/test/data/valid-config-files/debug-check-some.conf.in b/test/data/valid-config-files/debug-check-some.conf.in
2207 new file mode 100644
2208 index 0000000..47ee854
2210 +++ b/test/data/valid-config-files/debug-check-some.conf.in
2212 +<!-- Bus that listens on a debug pipe and doesn't create any restrictions -->
2214 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2215 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2217 + <listen>debug-pipe:name=test-server</listen>
2218 + <listen>@TEST_LISTEN@</listen>
2219 + <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
2220 + <policy context="default">
2221 + <allow send_interface="*"/>
2222 + <allow receive_interface="*"/>
2226 + <deny send_interface="org.freedesktop.TestSuite" send_member="Echo"/>
2227 + <check privilege="foo" send_interface="org.freedesktop.TestSuite" send_member="Echo"/>