1 From 8f69153081140fa4c347ab1729c348ec77b309ec 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: [PATCH 1/5] 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 Change-Id: I9bcbce34577e5dc2a3cecf6233a0a2b0e43e1108
23 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
26 bus/bus.c | 136 +++++---
28 bus/check.c | 217 ++++++++++++
30 bus/config-parser-common.c | 6 +
31 bus/config-parser-common.h | 1 +
32 bus/config-parser.c | 71 +++-
33 bus/connection.c | 56 ++-
34 bus/connection.h | 4 +
35 bus/cynara.c | 374 +++++++++++++++++++++
37 bus/dispatch.c | 44 ++-
38 bus/policy.c | 193 +++++++----
41 test/Makefile.am | 1 +
42 test/data/invalid-config-files/badcheck-1.conf | 9 +
43 test/data/invalid-config-files/badcheck-2.conf | 9 +
44 test/data/valid-config-files/check-1.conf | 9 +
45 .../valid-config-files/debug-check-some.conf.in | 18 +
46 tools/dbus-send.c | 2 +-
47 22 files changed, 1193 insertions(+), 163 deletions(-)
48 create mode 100644 bus/check.c
49 create mode 100644 bus/check.h
50 create mode 100644 bus/cynara.c
51 create mode 100644 bus/cynara.h
52 create mode 100644 test/data/invalid-config-files/badcheck-1.conf
53 create mode 100644 test/data/invalid-config-files/badcheck-2.conf
54 create mode 100644 test/data/valid-config-files/check-1.conf
55 create mode 100644 test/data/valid-config-files/debug-check-some.conf.in
57 diff --git a/bus/Makefile.am b/bus/Makefile.am
58 index 33af09b0..3f57cc48 100644
61 @@ -9,6 +9,7 @@ DBUS_BUS_LIBS = \
68 DBUS_LAUNCHER_LIBS = \
69 @@ -24,6 +25,7 @@ AM_CPPFLAGS = \
71 -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \
76 # if assertions are enabled, improve backtraces
77 @@ -82,12 +84,16 @@ BUS_SOURCES= \
85 config-parser-common.c \
86 config-parser-common.h \
94 diff --git a/bus/bus.c b/bus/bus.c
95 index fd4ab9e4..c4008505 100644
101 #include "dir-watch.h"
103 #include <dbus/dbus-list.h>
104 #include <dbus/dbus-hash.h>
105 #include <dbus/dbus-credentials.h>
106 @@ -65,6 +66,7 @@ struct BusContext
107 BusRegistry *registry;
109 BusMatchmaker *matchmaker;
112 DBusRLimit *initial_fd_limit;
113 unsigned int fork : 1;
114 @@ -988,6 +990,10 @@ bus_context_new (const DBusString *config_file,
118 + context->check = bus_check_new(context, error);
119 + if (context->check == NULL)
122 dbus_server_free_data_slot (&server_data_slot);
125 @@ -1112,6 +1118,12 @@ bus_context_unref (BusContext *context)
127 bus_context_shutdown (context);
129 + if (context->check)
131 + bus_check_unref(context->check);
132 + context->check = NULL;
135 if (context->connections)
137 bus_connections_unref (context->connections);
138 @@ -1241,6 +1253,12 @@ bus_context_get_loop (BusContext *context)
139 return context->loop;
143 +bus_context_get_check (BusContext *context)
145 + return context->check;
149 bus_context_allow_unix_user (BusContext *context,
151 @@ -1456,6 +1474,7 @@ complain_about_message (BusContext *context,
152 DBusConnection *proposed_recipient,
153 dbus_bool_t requested_reply,
155 + const char *privilege,
158 DBusError stack_error = DBUS_ERROR_INIT;
159 @@ -1485,7 +1504,8 @@ complain_about_message (BusContext *context,
160 dbus_set_error (&stack_error, error_name,
161 "%s, %d matched rules; type=\"%s\", sender=\"%s\" (%s) "
162 "interface=\"%s\" member=\"%s\" error name=\"%s\" "
163 - "requested_reply=\"%d\" destination=\"%s\" (%s)",
164 + "requested_reply=\"%d\" destination=\"%s\" (%s) "
165 + "privilege=\"%s\"",
168 dbus_message_type_to_string (dbus_message_get_type (message)),
169 @@ -1496,7 +1516,8 @@ complain_about_message (BusContext *context,
170 nonnull (dbus_message_get_error_name (message), "(unset)"),
172 nonnull (dbus_message_get_destination (message), DBUS_SERVICE_DBUS),
173 - proposed_recipient_loginfo);
174 + proposed_recipient_loginfo,
175 + nonnull (privilege, "(n/a)"));
177 /* If we hit OOM while setting the error, this will syslog "out of memory"
178 * which is itself an indication that something is seriously wrong */
179 @@ -1520,14 +1541,15 @@ complain_about_message (BusContext *context,
180 * NULL for addressed_recipient may mean the bus driver, or may mean
181 * no destination was specified in the message (e.g. a signal).
184 -bus_context_check_security_policy (BusContext *context,
185 - BusTransaction *transaction,
186 - DBusConnection *sender,
187 - DBusConnection *addressed_recipient,
188 - DBusConnection *proposed_recipient,
189 - DBusMessage *message,
192 +bus_context_check_security_policy (BusContext *context,
193 + BusTransaction *transaction,
194 + DBusConnection *sender,
195 + DBusConnection *addressed_recipient,
196 + DBusConnection *proposed_recipient,
197 + DBusMessage *message,
199 + BusDeferredMessage **deferred_message)
201 const char *src, *dest;
202 BusClientPolicy *sender_policy;
203 @@ -1536,6 +1558,7 @@ bus_context_check_security_policy (BusContext *context,
206 dbus_bool_t requested_reply;
207 + const char *privilege;
209 type = dbus_message_get_type (message);
210 src = dbus_message_get_sender (message);
211 @@ -1564,7 +1587,7 @@ bus_context_check_security_policy (BusContext *context,
212 dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
213 "Message bus will not accept messages of unknown type\n");
216 + return BUS_RESULT_FALSE;
219 requested_reply = FALSE;
220 @@ -1594,7 +1617,7 @@ bus_context_check_security_policy (BusContext *context,
221 if (dbus_error_is_set (&error2))
223 dbus_move_error (&error2, error);
225 + return BUS_RESULT_FALSE;
229 @@ -1621,11 +1644,11 @@ bus_context_check_security_policy (BusContext *context,
230 complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
231 "An SELinux policy prevents this sender from sending this "
232 "message to this recipient",
233 - 0, message, sender, proposed_recipient, FALSE, FALSE, error);
234 + 0, message, sender, proposed_recipient, FALSE, FALSE, NULL, error);
235 _dbus_verbose ("SELinux security check denying send to service\n");
239 + return BUS_RESULT_FALSE;
242 /* next verify AppArmor access controls. If allowed then
243 @@ -1642,7 +1665,7 @@ bus_context_check_security_policy (BusContext *context,
244 dest ? dest : DBUS_SERVICE_DBUS,
245 src ? src : DBUS_SERVICE_DBUS,
248 + return BUS_RESULT_FALSE;
250 if (!bus_connection_is_active (sender))
252 @@ -1656,7 +1679,7 @@ bus_context_check_security_policy (BusContext *context,
254 _dbus_verbose ("security check allowing %s message\n",
257 + return BUS_RESULT_TRUE;
261 @@ -1667,7 +1690,7 @@ bus_context_check_security_policy (BusContext *context,
262 "Client tried to send a message other than %s without being registered",
266 + return BUS_RESULT_FALSE;
270 @@ -1716,20 +1739,29 @@ bus_context_check_security_policy (BusContext *context,
271 (proposed_recipient == NULL && recipient_policy == NULL));
274 - if (sender_policy &&
275 - !bus_client_policy_check_can_send (sender_policy,
278 - proposed_recipient,
279 - message, &toggles, &log))
281 - complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
282 - "Rejected send message", toggles,
283 - message, sender, proposed_recipient, requested_reply,
284 - (addressed_recipient == proposed_recipient), error);
285 - _dbus_verbose ("security policy disallowing message due to sender policy\n");
290 + BusResult res = bus_client_policy_check_can_send (sender,
294 + addressed_recipient,
295 + proposed_recipient,
296 + message, &toggles, &log, &privilege,
298 + if (res == BUS_RESULT_FALSE)
300 + complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
301 + "Rejected send message", toggles,
302 + message, sender, proposed_recipient, requested_reply,
303 + (addressed_recipient == proposed_recipient), privilege,
305 + _dbus_verbose ("security policy disallowing message due to sender policy\n");
306 + return BUS_RESULT_FALSE;
308 + else if (res == BUS_RESULT_LATER)
309 + return BUS_RESULT_LATER;
314 @@ -1738,23 +1770,29 @@ bus_context_check_security_policy (BusContext *context,
315 complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
316 "Would reject message", toggles,
317 message, sender, proposed_recipient, requested_reply,
319 + TRUE, privilege, NULL);
322 - if (recipient_policy &&
323 - !bus_client_policy_check_can_receive (recipient_policy,
327 - addressed_recipient, proposed_recipient,
328 - message, &toggles))
329 + if (recipient_policy)
331 - complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
332 - "Rejected receive message", toggles,
333 - message, sender, proposed_recipient, requested_reply,
334 - (addressed_recipient == proposed_recipient), error);
335 - _dbus_verbose ("security policy disallowing message due to recipient policy\n");
338 + res = bus_client_policy_check_can_receive (recipient_policy,
342 + addressed_recipient, proposed_recipient,
343 + message, &toggles, &privilege, deferred_message);
344 + if (res == BUS_RESULT_FALSE)
346 + complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected receive message",
347 + toggles, message, sender, proposed_recipient, requested_reply,
348 + (addressed_recipient == proposed_recipient), privilege, error);
350 + "security policy disallowing message due to recipient policy\n");
351 + return BUS_RESULT_FALSE;
353 + else if (res == BUS_RESULT_LATER)
354 + return BUS_RESULT_LATER;
357 /* See if limits on size have been exceeded */
358 @@ -1764,10 +1802,10 @@ bus_context_check_security_policy (BusContext *context,
360 complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
361 "Rejected: destination has a full message queue",
362 - 0, message, sender, proposed_recipient, requested_reply, TRUE,
363 + 0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
365 _dbus_verbose ("security policy disallowing message due to full message queue\n");
367 + return BUS_RESULT_FALSE;
370 /* Record that we will allow a reply here in the future (don't
371 @@ -1784,11 +1822,11 @@ bus_context_check_security_policy (BusContext *context,
374 _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
376 + return BUS_RESULT_FALSE;
379 _dbus_verbose ("security policy allowing message\n");
381 + return BUS_RESULT_TRUE;
385 diff --git a/bus/bus.h b/bus/bus.h
386 index 3fab59ff..dab7791f 100644
389 @@ -44,6 +44,22 @@ typedef struct BusOwner BusOwner;
390 typedef struct BusTransaction BusTransaction;
391 typedef struct BusMatchmaker BusMatchmaker;
392 typedef struct BusMatchRule BusMatchRule;
393 +typedef struct BusCheck BusCheck;
394 +typedef struct BusDeferredMessage BusDeferredMessage;
395 +typedef struct BusCynara BusCynara;
398 + * BusResult is defined as a pointer to a dummy structure to allow detection of type mismatches.
399 + * The disadvantage of such solution is that now BusResult variables cannot be used in switch
401 + * Additionally, BUS_RESULT_TRUE is defined as 0 instead of 1 to help detect type mismatches
404 +typedef const struct BusResultStruct { int dummy; } *BusResult;
406 +static const BusResult BUS_RESULT_TRUE = (BusResult)0x0;
407 +static const BusResult BUS_RESULT_FALSE = (BusResult)0x1;
408 +static const BusResult BUS_RESULT_LATER = (BusResult)0x2;
412 @@ -97,6 +113,7 @@ BusConnections* bus_context_get_connections (BusContext
413 BusActivation* bus_context_get_activation (BusContext *context);
414 BusMatchmaker* bus_context_get_matchmaker (BusContext *context);
415 DBusLoop* bus_context_get_loop (BusContext *context);
416 +BusCheck * bus_context_get_check (BusContext *context);
417 dbus_bool_t bus_context_allow_unix_user (BusContext *context,
419 dbus_bool_t bus_context_allow_windows_user (BusContext *context,
420 @@ -131,13 +148,14 @@ void bus_context_log_and_set_error (BusContext
423 ...) _DBUS_GNUC_PRINTF (5, 6);
424 -dbus_bool_t bus_context_check_security_policy (BusContext *context,
425 - BusTransaction *transaction,
426 - DBusConnection *sender,
427 - DBusConnection *addressed_recipient,
428 - DBusConnection *proposed_recipient,
429 - DBusMessage *message,
431 +BusResult bus_context_check_security_policy (BusContext *context,
432 + BusTransaction *transaction,
433 + DBusConnection *sender,
434 + DBusConnection *addressed_recipient,
435 + DBusConnection *proposed_recipient,
436 + DBusMessage *message,
438 + BusDeferredMessage **deferred_message);
439 void bus_context_check_all_watches (BusContext *context);
441 #endif /* BUS_BUS_H */
442 diff --git a/bus/check.c b/bus/check.c
444 index 00000000..5b72d31c
448 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
449 +/* check.c Bus security policy runtime check
451 + * Copyright (C) 2014 Intel, Inc.
452 + * Copyright (c) 2014 Samsung Electronics, Ltd.
454 + * Licensed under the Academic Free License version 2.1
456 + * This program is free software; you can redistribute it and/or modify
457 + * it under the terms of the GNU General Public License as published by
458 + * the Free Software Foundation; either version 2 of the License, or
459 + * (at your option) any later version.
461 + * This program is distributed in the hope that it will be useful,
462 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
463 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
464 + * GNU General Public License for more details.
466 + * You should have received a copy of the GNU General Public License
467 + * along with this program; if not, write to the Free Software
468 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
474 +#include "connection.h"
475 +#include "dispatch.h"
478 +#include <dbus/dbus-connection-internal.h>
479 +#include <dbus/dbus-message-internal.h>
480 +#include <dbus/dbus-internals.h>
483 +typedef struct BusCheck
487 + BusContext *context;
491 +typedef struct BusDeferredMessage
495 + DBusMessage *message;
496 + DBusConnection *sender;
497 + DBusConnection *proposed_recipient;
498 + DBusConnection *addressed_recipient;
499 + dbus_bool_t full_dispatch;
500 + BusDeferredMessageStatus status;
501 + BusResult response;
502 + BusCheckResponseFunc response_callback;
503 +} BusDeferredMessage;
506 +bus_check_new (BusContext *context, DBusError *error)
510 + check = dbus_new(BusCheck, 1);
513 + BUS_SET_OOM(error);
517 + check->refcount = 1;
518 + check->context = context;
519 + check->cynara = bus_cynara_new(check, error);
520 + if (dbus_error_is_set(error))
530 +bus_check_ref (BusCheck *check)
532 + _dbus_assert (check->refcount > 0);
533 + check->refcount += 1;
539 +bus_check_unref (BusCheck *check)
541 + _dbus_assert (check->refcount > 0);
543 + check->refcount -= 1;
545 + if (check->refcount == 0)
547 + bus_cynara_unref(check->cynara);
553 +bus_check_get_context (BusCheck *check)
555 + return check->context;
559 +bus_check_get_cynara (BusCheck *check)
561 + return check->cynara;
565 +bus_check_privilege (BusCheck *check,
566 + DBusMessage *message,
567 + DBusConnection *sender,
568 + DBusConnection *addressed_recipient,
569 + DBusConnection *proposed_recipient,
570 + const char *privilege,
571 + BusDeferredMessageStatus check_type,
572 + BusDeferredMessage **deferred_message)
574 + BusResult result = BUS_RESULT_FALSE;
575 +#ifdef DBUS_ENABLE_CYNARA
578 + DBusConnection *connection;
580 + connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
582 + if (!dbus_connection_get_is_connected(connection))
584 + return BUS_RESULT_FALSE;
587 + /* ask policy checkers */
588 +#ifdef DBUS_ENABLE_CYNARA
589 + cynara = bus_check_get_cynara(check);
590 + result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
591 + proposed_recipient, privilege, check_type, deferred_message);
594 + if (result == BUS_RESULT_LATER && deferred_message != NULL)
596 + (*deferred_message)->status |= check_type;
601 +BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
602 + DBusConnection *sender,
603 + DBusConnection *addressed_recipient,
604 + DBusConnection *proposed_recipient,
605 + BusResult response)
607 + BusDeferredMessage *deferred_message;
609 + deferred_message = dbus_new(BusDeferredMessage, 1);
610 + if (deferred_message == NULL)
615 + deferred_message->refcount = 1;
616 + deferred_message->sender = sender != NULL ? dbus_connection_ref(sender) : NULL;
617 + deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
618 + deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
619 + deferred_message->message = dbus_message_ref(message);
620 + deferred_message->response = response;
621 + deferred_message->status = 0;
622 + deferred_message->full_dispatch = FALSE;
623 + deferred_message->response_callback = NULL;
625 + return deferred_message;
628 +BusDeferredMessage *
629 +bus_deferred_message_ref (BusDeferredMessage *deferred_message)
631 + _dbus_assert (deferred_message->refcount > 0);
632 + deferred_message->refcount += 1;
633 + return deferred_message;
637 +bus_deferred_message_unref (BusDeferredMessage *deferred_message)
639 + _dbus_assert (deferred_message->refcount > 0);
641 + deferred_message->refcount -= 1;
643 + if (deferred_message->refcount == 0)
645 + dbus_message_unref(deferred_message->message);
646 + if (deferred_message->sender != NULL)
647 + dbus_connection_unref(deferred_message->sender);
648 + if (deferred_message->addressed_recipient != NULL)
649 + dbus_connection_unref(deferred_message->addressed_recipient);
650 + if (deferred_message->proposed_recipient != NULL)
651 + dbus_connection_unref(deferred_message->proposed_recipient);
652 + dbus_free(deferred_message);
657 +bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
660 + if (deferred_message->response_callback != NULL)
662 + deferred_message->response_callback(deferred_message, result);
665 diff --git a/bus/check.h b/bus/check.h
667 index 00000000..c3fcaf90
671 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
672 +/* check.h Bus security policy runtime check
674 + * Copyright (C) 2014 Intel, Inc.
675 + * Copyright (c) 2014 Samsung Electronics, Ltd.
677 + * Licensed under the Academic Free License version 2.1
679 + * This program is free software; you can redistribute it and/or modify
680 + * it under the terms of the GNU General Public License as published by
681 + * the Free Software Foundation; either version 2 of the License, or
682 + * (at your option) any later version.
684 + * This program is distributed in the hope that it will be useful,
685 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
686 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
687 + * GNU General Public License for more details.
689 + * You should have received a copy of the GNU General Public License
690 + * along with this program; if not, write to the Free Software
691 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
702 +typedef void (*BusCheckResponseFunc) (BusDeferredMessage *message,
706 + BUS_DEFERRED_MESSAGE_CHECK_SEND = 1 << 0,
707 + BUS_DEFERRED_MESSAGE_CHECK_RECEIVE = 1 << 1,
708 + BUS_DEFERRED_MESSAGE_CHECK_OWN = 1 << 2,
709 +} BusDeferredMessageStatus;
712 +BusCheck *bus_check_new (BusContext *context,
714 +BusCheck *bus_check_ref (BusCheck *check);
715 +void bus_check_unref (BusCheck *check);
717 +BusContext *bus_check_get_context (BusCheck *check);
718 +BusCynara *bus_check_get_cynara (BusCheck *check);
719 +BusResult bus_check_privilege (BusCheck *check,
720 + DBusMessage *message,
721 + DBusConnection *sender,
722 + DBusConnection *addressed_recipient,
723 + DBusConnection *proposed_recipient,
724 + const char *privilege,
725 + BusDeferredMessageStatus check_type,
726 + BusDeferredMessage **deferred_message);
728 +BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
729 + DBusConnection *sender,
730 + DBusConnection *addressed_recipient,
731 + DBusConnection *proposed_recipient,
732 + BusResult response);
734 +BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message);
735 +void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
736 +void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
738 +#endif /* BUS_CHECK_H */
739 diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
740 index 5db6b289..ea25f5e6 100644
741 --- a/bus/config-parser-common.c
742 +++ b/bus/config-parser-common.c
743 @@ -75,6 +75,10 @@ bus_config_parser_element_name_to_type (const char *name)
747 + else if (strcmp (name, "check") == 0)
749 + return ELEMENT_CHECK;
751 else if (strcmp (name, "servicehelper") == 0)
753 return ELEMENT_SERVICEHELPER;
754 @@ -159,6 +163,8 @@ bus_config_parser_element_type_to_name (ElementType type)
758 + case ELEMENT_CHECK:
762 case ELEMENT_PIDFILE:
763 diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
764 index 382a0141..9e026d10 100644
765 --- a/bus/config-parser-common.h
766 +++ b/bus/config-parser-common.h
767 @@ -36,6 +36,7 @@ typedef enum
775 diff --git a/bus/config-parser.c b/bus/config-parser.c
776 index d9f6042c..a8c4ca5d 100644
777 --- a/bus/config-parser.c
778 +++ b/bus/config-parser.c
779 @@ -1172,7 +1172,7 @@ append_rule_from_element (BusConfigParser *parser,
780 const char *element_name,
781 const char **attribute_names,
782 const char **attribute_values,
784 + BusPolicyRuleAccess access,
788 @@ -1195,6 +1195,7 @@ append_rule_from_element (BusConfigParser *parser,
789 const char *own_prefix;
792 + const char *privilege;
796 @@ -1222,6 +1223,7 @@ append_rule_from_element (BusConfigParser *parser,
800 + "privilege", &privilege,
804 @@ -1230,6 +1232,7 @@ append_rule_from_element (BusConfigParser *parser,
805 receive_interface || receive_member || receive_error || receive_sender ||
806 receive_type || receive_path || eavesdrop ||
807 send_requested_reply || receive_requested_reply ||
809 own || own_prefix || user || group))
811 dbus_set_error (error, DBUS_ERROR_FAILED,
812 @@ -1246,7 +1249,30 @@ append_rule_from_element (BusConfigParser *parser,
818 + if (access == BUS_POLICY_RULE_ACCESS_CHECK)
820 + if (privilege == NULL || !*privilege)
822 + dbus_set_error (error, DBUS_ERROR_FAILED,
823 + "On element <%s>, you must specify the privilege to be checked.",
830 + if (privilege != NULL && *privilege)
832 + dbus_set_error (error, DBUS_ERROR_FAILED,
833 + "On element <%s>, privilege %s is used outside of a check rule.",
834 + element_name, privilege);
838 + privilege = NULL; /* replace (potentially) empty string with NULL pointer, it wouldn't be used anyway */
841 /* Allowed combinations of elements are:
843 * base, must be all send or all receive:
844 @@ -1420,7 +1446,7 @@ append_rule_from_element (BusConfigParser *parser,
848 - rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
849 + rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, access);
853 @@ -1502,7 +1528,7 @@ append_rule_from_element (BusConfigParser *parser,
857 - rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
858 + rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, access);
862 @@ -1532,7 +1558,7 @@ append_rule_from_element (BusConfigParser *parser,
864 else if (own || own_prefix)
866 - rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow);
867 + rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, access);
871 @@ -1558,7 +1584,7 @@ append_rule_from_element (BusConfigParser *parser,
873 if (IS_WILDCARD (user))
875 - rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
876 + rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
880 @@ -1573,7 +1599,7 @@ append_rule_from_element (BusConfigParser *parser,
882 if (_dbus_parse_unix_user_from_config (&username, &uid))
884 - rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
885 + rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
889 @@ -1590,7 +1616,7 @@ append_rule_from_element (BusConfigParser *parser,
891 if (IS_WILDCARD (group))
893 - rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
894 + rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
898 @@ -1605,7 +1631,7 @@ append_rule_from_element (BusConfigParser *parser,
900 if (_dbus_parse_unix_group_from_config (&groupname, &gid))
902 - rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
903 + rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
907 @@ -1629,6 +1655,10 @@ append_rule_from_element (BusConfigParser *parser,
908 _dbus_assert (pe != NULL);
909 _dbus_assert (pe->type == ELEMENT_POLICY);
911 + rule->privilege = _dbus_strdup (privilege);
912 + if (privilege && !rule->privilege)
915 switch (pe->d.policy.type)
918 @@ -1703,7 +1733,7 @@ start_policy_child (BusConfigParser *parser,
920 if (!append_rule_from_element (parser, element_name,
921 attribute_names, attribute_values,
923 + BUS_POLICY_RULE_ACCESS_ALLOW, error))
926 if (push_element (parser, ELEMENT_ALLOW) == NULL)
927 @@ -1718,7 +1748,7 @@ start_policy_child (BusConfigParser *parser,
929 if (!append_rule_from_element (parser, element_name,
930 attribute_names, attribute_values,
932 + BUS_POLICY_RULE_ACCESS_DENY, error))
935 if (push_element (parser, ELEMENT_DENY) == NULL)
936 @@ -1727,6 +1757,21 @@ start_policy_child (BusConfigParser *parser,
942 + else if (strcmp (element_name, "check") == 0)
944 + if (!append_rule_from_element (parser, element_name,
945 + attribute_names, attribute_values,
946 + BUS_POLICY_RULE_ACCESS_CHECK, error))
949 + if (push_element (parser, ELEMENT_CHECK) == NULL)
951 + BUS_SET_OOM (error);
958 @@ -2088,6 +2133,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
962 + case ELEMENT_CHECK:
965 case ELEMENT_KEEP_UMASK:
966 @@ -2397,6 +2443,7 @@ bus_config_parser_content (BusConfigParser *parser,
970 + case ELEMENT_CHECK:
973 case ELEMENT_KEEP_UMASK:
974 @@ -2862,6 +2909,8 @@ do_load (const DBusString *full_path,
975 dbus_error_init (&error);
977 parser = bus_config_load (full_path, TRUE, NULL, &error);
978 + if (dbus_error_is_set (&error))
979 + _dbus_verbose ("Failed to load file: %s\n", error.message);
982 _DBUS_ASSERT_ERROR_IS_SET (&error);
983 diff --git a/bus/connection.c b/bus/connection.c
984 index 02d6c220..eea50ecd 100644
985 --- a/bus/connection.c
986 +++ b/bus/connection.c
988 #include <dbus/dbus-timeout.h>
989 #include <dbus/dbus-connection-internal.h>
990 #include <dbus/dbus-internals.h>
991 +#ifdef DBUS_ENABLE_CYNARA
993 +#include <cynara-session.h>
996 /* Trim executed commands to this length; we want to keep logs readable */
997 #define MAX_LOG_COMMAND_LEN 50
998 @@ -116,6 +120,9 @@ typedef struct
1000 /** non-NULL if and only if this is a monitor */
1001 DBusList *link_in_monitors;
1002 +#ifdef DBUS_ENABLE_CYNARA
1003 + char *cynara_session_id;
1005 } BusConnectionData;
1007 static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
1008 @@ -129,8 +136,8 @@ static dbus_bool_t expire_incomplete_timeout (void *data);
1010 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
1013 -connection_get_loop (DBusConnection *connection)
1015 +bus_connection_get_loop (DBusConnection *connection)
1017 BusConnectionData *d;
1019 @@ -354,7 +361,7 @@ add_connection_watch (DBusWatch *watch,
1021 DBusConnection *connection = data;
1023 - return _dbus_loop_add_watch (connection_get_loop (connection), watch);
1024 + return _dbus_loop_add_watch (bus_connection_get_loop (connection), watch);
1028 @@ -363,7 +370,7 @@ remove_connection_watch (DBusWatch *watch,
1030 DBusConnection *connection = data;
1032 - _dbus_loop_remove_watch (connection_get_loop (connection), watch);
1033 + _dbus_loop_remove_watch (bus_connection_get_loop (connection), watch);
1037 @@ -372,7 +379,7 @@ toggle_connection_watch (DBusWatch *watch,
1039 DBusConnection *connection = data;
1041 - _dbus_loop_toggle_watch (connection_get_loop (connection), watch);
1042 + _dbus_loop_toggle_watch (bus_connection_get_loop (connection), watch);
1046 @@ -381,7 +388,7 @@ add_connection_timeout (DBusTimeout *timeout,
1048 DBusConnection *connection = data;
1050 - return _dbus_loop_add_timeout (connection_get_loop (connection), timeout);
1051 + return _dbus_loop_add_timeout (bus_connection_get_loop (connection), timeout);
1055 @@ -390,7 +397,7 @@ remove_connection_timeout (DBusTimeout *timeout,
1057 DBusConnection *connection = data;
1059 - _dbus_loop_remove_timeout (connection_get_loop (connection), timeout);
1060 + _dbus_loop_remove_timeout (bus_connection_get_loop (connection), timeout);
1064 @@ -451,6 +458,10 @@ free_connection_data (void *data)
1066 dbus_free (d->name);
1068 +#ifdef DBUS_ENABLE_CYNARA
1069 + free (d->cynara_session_id);
1075 @@ -1063,6 +1074,22 @@ bus_connection_get_policy (DBusConnection *connection)
1079 +#ifdef DBUS_ENABLE_CYNARA
1080 +const char *bus_connection_get_cynara_session_id (DBusConnection *connection)
1082 + BusConnectionData *d = BUS_CONNECTION_DATA (connection);
1083 + _dbus_assert (d != NULL);
1085 + if (d->cynara_session_id == NULL)
1087 + unsigned long pid;
1088 + if (dbus_connection_get_unix_process_id(connection, &pid))
1089 + d->cynara_session_id = cynara_session_from_pid(pid);
1091 + return d->cynara_session_id;
1096 foreach_active (BusConnections *connections,
1097 BusConnectionForeachFunction function,
1098 @@ -2289,6 +2316,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
1099 DBusMessage *message)
1101 DBusError error = DBUS_ERROR_INIT;
1104 /* We have to set the sender to the driver, and have
1105 * to check security policy since it was not done in
1106 @@ -2326,9 +2354,11 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
1107 * if we're actively capturing messages, it's nice to log that we
1108 * tried to send it and did not allow ourselves to do so.
1110 - if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
1112 - NULL, connection, connection, message, &error))
1113 + res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
1115 + NULL, connection, connection, message, &error,
1117 + if (res == BUS_RESULT_FALSE)
1119 if (!bus_transaction_capture_error_reply (transaction, &error, message))
1121 @@ -2342,6 +2372,12 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
1122 dbus_error_free (&error);
1125 + else if (res == BUS_RESULT_LATER)
1127 + _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
1128 + dbus_error_free (&error);
1132 return bus_transaction_send (transaction, connection, message);
1134 diff --git a/bus/connection.h b/bus/connection.h
1135 index 8c68d0a0..a6e5dfde 100644
1136 --- a/bus/connection.h
1137 +++ b/bus/connection.h
1139 typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection,
1142 +DBusLoop* bus_connection_get_loop (DBusConnection *connection);
1144 BusConnections* bus_connections_new (BusContext *context);
1145 BusConnections* bus_connections_ref (BusConnections *connections);
1146 @@ -122,6 +123,9 @@ dbus_bool_t bus_connection_be_monitor (DBusConnection *connection,
1147 BusTransaction *transaction,
1150 +#ifdef DBUS_ENABLE_CYNARA
1151 +const char *bus_connection_get_cynara_session_id (DBusConnection *connection);
1154 /* transaction API so we can send or not send a block of messages as a whole */
1156 diff --git a/bus/cynara.c b/bus/cynara.c
1157 new file mode 100644
1158 index 00000000..57a4c45c
1162 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
1163 +/* cynara.c Cynara runtime privilege checking
1165 + * Copyright (c) 2014 Samsung Electronics, Ltd.
1167 + * Licensed under the Academic Free License version 2.1
1169 + * This program is free software; you can redistribute it and/or modify
1170 + * it under the terms of the GNU General Public License as published by
1171 + * the Free Software Foundation; either version 2 of the License, or
1172 + * (at your option) any later version.
1174 + * This program is distributed in the hope that it will be useful,
1175 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1176 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1177 + * GNU General Public License for more details.
1179 + * You should have received a copy of the GNU General Public License
1180 + * along with this program; if not, write to the Free Software
1181 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1185 +#include <config.h>
1186 +#include "cynara.h"
1192 +#include <dbus/dbus.h>
1193 +#include <dbus/dbus-watch.h>
1194 +#include <dbus/dbus-connection-internal.h>
1195 +#include <bus/connection.h>
1196 +#ifdef DBUS_ENABLE_CYNARA
1197 +#include <cynara-client-async.h>
1201 +#ifdef DBUS_ENABLE_CYNARA
1202 +typedef struct BusCynara
1206 + BusContext *context;
1208 + cynara_async *cynara;
1209 + DBusWatch *cynara_watch;
1212 +#define USE_CYNARA_CACHE 1
1213 +#ifdef USE_CYNARA_CACHE
1214 +#define CYNARA_CACHE_SIZE 1000
1217 +static dbus_bool_t bus_cynara_watch_callback(DBusWatch *watch,
1218 + unsigned int flags,
1221 +static void status_callback(int old_fd,
1223 + cynara_async_status status,
1224 + void *user_status_data);
1225 +static void bus_cynara_check_response_callback (cynara_check_id check_id,
1226 + cynara_async_call_cause cause,
1228 + void *user_response_data);
1233 +bus_cynara_new(BusCheck *check, DBusError *error)
1235 +#ifdef DBUS_ENABLE_CYNARA
1236 + BusContext *context;
1237 + BusCynara *cynara;
1238 + cynara_async_configuration *conf = NULL;
1241 + cynara = dbus_new(BusCynara, 1);
1242 + if (cynara == NULL)
1244 + BUS_SET_OOM(error);
1248 + context = bus_check_get_context(check);
1250 + cynara->refcount = 1;
1251 + cynara->check = check;
1252 + cynara->context = context;
1253 + cynara->cynara_watch = NULL;
1255 + ret = cynara_async_configuration_create(&conf);
1256 + if (ret != CYNARA_API_SUCCESS)
1258 + dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to create Cynara configuration");
1262 +#ifdef CYNARA_CACHE_SIZE
1263 + ret = cynara_async_configuration_set_cache_size(conf, CYNARA_CACHE_SIZE);
1264 + if (ret != CYNARA_API_SUCCESS)
1266 + dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to Cynara cache size");
1271 + ret = cynara_async_initialize(&cynara->cynara, conf, &status_callback, cynara);
1272 + if (ret != CYNARA_API_SUCCESS)
1274 + dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to initialize Cynara client");
1279 + cynara_async_configuration_destroy(conf);
1280 + if (ret != CYNARA_API_SUCCESS)
1282 + dbus_free(cynara);
1293 +bus_cynara_ref (BusCynara *cynara)
1295 +#ifdef DBUS_ENABLE_CYNARA
1296 + _dbus_assert (cynara->refcount > 0);
1297 + cynara->refcount += 1;
1306 +bus_cynara_unref (BusCynara *cynara)
1308 +#ifdef DBUS_ENABLE_CYNARA
1309 + _dbus_assert (cynara->refcount > 0);
1311 + cynara->refcount -= 1;
1313 + if (cynara->refcount == 0)
1315 + cynara_async_finish(cynara->cynara);
1316 + dbus_free(cynara);
1322 +bus_cynara_check_privilege (BusCynara *cynara,
1323 + DBusMessage *message,
1324 + DBusConnection *sender,
1325 + DBusConnection *addressed_recipient,
1326 + DBusConnection *proposed_recipient,
1327 + const char *privilege,
1328 + BusDeferredMessageStatus check_type,
1329 + BusDeferredMessage **deferred_message_param)
1331 +#ifdef DBUS_ENABLE_CYNARA
1333 + unsigned long uid;
1335 + const char *session_id;
1337 + cynara_check_id check_id;
1338 + DBusConnection *connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
1339 + BusDeferredMessage *deferred_message;
1342 + _dbus_assert(connection != NULL);
1344 + if (dbus_connection_get_unix_user(connection, &uid) == FALSE)
1345 + return BUS_RESULT_FALSE;
1347 + if (_dbus_connection_get_linux_security_label(connection, &label) == FALSE || label == NULL)
1349 + _dbus_warn("Failed to obtain security label for connection\n");
1350 + return BUS_RESULT_FALSE;
1353 + session_id = bus_connection_get_cynara_session_id (connection);
1354 + if (session_id == NULL)
1356 + ret = BUS_RESULT_FALSE;
1360 + snprintf(user, sizeof(user), "%lu", uid);
1362 +#if USE_CYNARA_CACHE
1363 + result = cynara_async_check_cache(cynara->cynara, label, session_id, user, privilege);
1365 + result = CYNARA_API_CACHE_MISS;
1370 + case CYNARA_API_ACCESS_ALLOWED:
1371 + _dbus_verbose("Cynara: got ALLOWED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
1372 + label, session_id, user, privilege);
1373 + ret = BUS_RESULT_TRUE;
1376 + case CYNARA_API_ACCESS_DENIED:
1377 + _dbus_verbose("Cynara: got DENIED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
1378 + label, session_id, user, privilege);
1379 + ret = BUS_RESULT_FALSE;
1382 + case CYNARA_API_CACHE_MISS:
1383 + deferred_message = bus_deferred_message_new(message, sender, addressed_recipient,
1384 + proposed_recipient, BUS_RESULT_LATER);
1385 + if (deferred_message == NULL)
1387 + _dbus_verbose("Failed to allocate memory for deferred message\n");
1388 + ret = BUS_RESULT_FALSE;
1392 + /* callback is supposed to unref deferred_message*/
1393 + result = cynara_async_create_request(cynara->cynara, label, session_id, user, privilege, &check_id,
1394 + &bus_cynara_check_response_callback, deferred_message);
1395 + if (result == CYNARA_API_SUCCESS)
1397 + _dbus_verbose("Created Cynara request: client=%s session_id=%s user=%s privilege=%s check_id=%u "
1398 + "deferred_message=%p\n", label, session_id, user, privilege, (unsigned int)check_id, deferred_message);
1399 + if (deferred_message_param != NULL)
1400 + *deferred_message_param = deferred_message;
1401 + ret = BUS_RESULT_LATER;
1405 + _dbus_verbose("Error on cynara request create: %i\n", result);
1406 + bus_deferred_message_unref(deferred_message);
1407 + ret = BUS_RESULT_FALSE;
1411 + _dbus_verbose("Error when accessing Cynara cache: %i\n", result);
1412 + ret = BUS_RESULT_FALSE;
1419 + return BUS_RESULT_FALSE;
1425 +#ifdef DBUS_ENABLE_CYNARA
1427 +status_callback(int old_fd, int new_fd, cynara_async_status status,
1428 + void *user_status_data)
1430 + BusCynara *cynara = (BusCynara *)user_status_data;
1431 + DBusLoop *loop = bus_context_get_loop(cynara->context);
1433 + if (cynara->cynara_watch != NULL)
1435 + _dbus_loop_remove_watch(loop, cynara->cynara_watch);
1436 + _dbus_watch_invalidate(cynara->cynara_watch);
1437 + _dbus_watch_unref(cynara->cynara_watch);
1438 + cynara->cynara_watch = NULL;
1443 + unsigned int flags;
1448 + case CYNARA_STATUS_FOR_READ:
1449 + flags = DBUS_WATCH_READABLE;
1451 + case CYNARA_STATUS_FOR_RW:
1452 + flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
1455 + /* Cynara passed unknown status - warn and add RW watch */
1456 + _dbus_verbose("Cynara passed unknown status value: 0x%08X\n", (unsigned int)status);
1457 + flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
1461 + watch = _dbus_watch_new(new_fd, flags, TRUE, &bus_cynara_watch_callback, cynara, NULL);
1462 + if (watch != NULL)
1464 + if (_dbus_loop_add_watch(loop, watch) == TRUE)
1466 + cynara->cynara_watch = watch;
1470 + _dbus_watch_invalidate(watch);
1471 + _dbus_watch_unref(watch);
1474 + /* It seems like not much can be done at this point. Cynara events won't be processed
1475 + * until next Cynara function call triggering status callback */
1476 + _dbus_verbose("Failed to add dbus watch\n");
1481 +bus_cynara_watch_callback(DBusWatch *watch,
1482 + unsigned int flags,
1485 + BusCynara *cynara = (BusCynara *)data;
1486 + int result = cynara_async_process(cynara->cynara);
1487 + if (result != CYNARA_API_SUCCESS)
1488 + _dbus_verbose("cynara_async_process returned %d\n", result);
1490 + return result != CYNARA_API_OUT_OF_MEMORY ? TRUE : FALSE;
1493 +static inline const char *
1494 +call_cause_to_string(cynara_async_call_cause cause)
1498 + case CYNARA_CALL_CAUSE_ANSWER:
1500 + case CYNARA_CALL_CAUSE_CANCEL:
1502 + case CYNARA_CALL_CAUSE_FINISH:
1504 + case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE:
1505 + return "SERVICE NOT AVAILABLE";
1512 +bus_cynara_check_response_callback (cynara_check_id check_id,
1513 + cynara_async_call_cause cause,
1515 + void *user_response_data)
1517 + BusDeferredMessage *deferred_message = user_response_data;
1520 + _dbus_verbose("Cynara callback: check_id=%u, cause=%s response=%i response_data=%p\n",
1521 + (unsigned int)check_id, call_cause_to_string(cause), response, user_response_data);
1523 + if (deferred_message == NULL)
1526 + if (cause == CYNARA_CALL_CAUSE_ANSWER && response == CYNARA_API_ACCESS_ALLOWED)
1527 + result = BUS_RESULT_TRUE;
1529 + result = BUS_RESULT_FALSE;
1531 + bus_deferred_message_response_received(deferred_message, result);
1532 + bus_deferred_message_unref(deferred_message);
1535 +#endif /* DBUS_ENABLE_CYNARA */
1536 diff --git a/bus/cynara.h b/bus/cynara.h
1537 new file mode 100644
1538 index 00000000..c4728bb7
1542 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
1543 +/* cynara.h Cynara runtime privilege checking
1545 + * Copyright (c) 2014 Samsung Electronics, Ltd.
1547 + * Licensed under the Academic Free License version 2.1
1549 + * This program is free software; you can redistribute it and/or modify
1550 + * it under the terms of the GNU General Public License as published by
1551 + * the Free Software Foundation; either version 2 of the License, or
1552 + * (at your option) any later version.
1554 + * This program is distributed in the hope that it will be useful,
1555 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1556 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1557 + * GNU General Public License for more details.
1559 + * You should have received a copy of the GNU General Public License
1560 + * along with this program; if not, write to the Free Software
1561 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1568 +BusCynara *bus_cynara_new (BusCheck *check, DBusError *error);
1569 +BusCynara *bus_cynara_ref (BusCynara *cynara);
1570 +void bus_cynara_unref (BusCynara *cynara);
1571 +BusResult bus_cynara_check_privilege (BusCynara *cynara,
1572 + DBusMessage *message,
1573 + DBusConnection *sender,
1574 + DBusConnection *addressed_recipient,
1575 + DBusConnection *proposed_recipient,
1576 + const char *privilege,
1577 + BusDeferredMessageStatus check_type,
1578 + BusDeferredMessage **deferred_message);
1579 diff --git a/bus/dispatch.c b/bus/dispatch.c
1580 index edfa1b44..05be3bdf 100644
1581 --- a/bus/dispatch.c
1582 +++ b/bus/dispatch.c
1586 #include "dispatch.h"
1588 #include "connection.h"
1590 #include "services.h"
1591 @@ -64,13 +65,17 @@ send_one_message (DBusConnection *connection,
1594 DBusError stack_error = DBUS_ERROR_INIT;
1595 + BusDeferredMessage *deferred_message;
1598 - if (!bus_context_check_security_policy (context, transaction,
1599 + result = bus_context_check_security_policy (context, transaction,
1601 addressed_recipient,
1606 + &deferred_message);
1607 + if (result != BUS_RESULT_TRUE)
1609 if (!bus_transaction_capture_error_reply (transaction, &stack_error,
1611 @@ -129,6 +134,7 @@ bus_dispatch_matches (BusTransaction *transaction,
1612 BusMatchmaker *matchmaker;
1614 BusContext *context;
1615 + BusDeferredMessage *deferred_message;
1617 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1619 @@ -144,11 +150,21 @@ bus_dispatch_matches (BusTransaction *transaction,
1620 /* First, send the message to the addressed_recipient, if there is one. */
1621 if (addressed_recipient != NULL)
1623 - if (!bus_context_check_security_policy (context, transaction,
1624 - sender, addressed_recipient,
1625 - addressed_recipient,
1628 + res = bus_context_check_security_policy (context, transaction,
1629 + sender, addressed_recipient,
1630 + addressed_recipient,
1632 + &deferred_message);
1633 + if (res == BUS_RESULT_FALSE)
1635 + else if (res == BUS_RESULT_LATER)
1637 + dbus_set_error (error,
1638 + DBUS_ERROR_ACCESS_DENIED,
1639 + "Rejecting message because time is needed to check security policy");
1643 if (dbus_message_contains_unix_fds (message) &&
1644 !dbus_connection_can_send_type (addressed_recipient,
1645 @@ -379,12 +395,24 @@ bus_dispatch (DBusConnection *connection,
1647 strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
1649 - if (!bus_context_check_security_policy (context, transaction,
1650 - connection, NULL, NULL, message, &error))
1651 + BusDeferredMessage *deferred_message;
1653 + res = bus_context_check_security_policy (context, transaction,
1654 + connection, NULL, NULL, message, &error,
1655 + &deferred_message);
1656 + if (res == BUS_RESULT_FALSE)
1658 _dbus_verbose ("Security policy rejected message\n");
1661 + else if (res == BUS_RESULT_LATER)
1663 + dbus_set_error (&error,
1664 + DBUS_ERROR_ACCESS_DENIED,
1665 + "Rejecting message because time is needed to check security policy");
1666 + _dbus_verbose ("Security policy needs time to check policy. Dropping message\n");
1670 _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS);
1671 if (!bus_driver_handle_message (connection, transaction, message, &error))
1672 diff --git a/bus/policy.c b/bus/policy.c
1673 index 082f3853..bcade176 100644
1682 #include "services.h"
1687 bus_policy_rule_new (BusPolicyRuleType type,
1688 - dbus_bool_t allow)
1689 + BusPolicyRuleAccess access)
1691 BusPolicyRule *rule;
1693 @@ -42,7 +43,7 @@ bus_policy_rule_new (BusPolicyRuleType type,
1697 - rule->allow = allow;
1698 + rule->access = access;
1702 @@ -54,18 +55,19 @@ bus_policy_rule_new (BusPolicyRuleType type,
1704 case BUS_POLICY_RULE_SEND:
1705 rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
1707 /* allow rules default to TRUE (only requested replies allowed)
1708 + * check rules default to TRUE (only requested replies are checked)
1709 * deny rules default to FALSE (only unrequested replies denied)
1711 - rule->d.send.requested_reply = rule->allow;
1712 + rule->d.send.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
1714 case BUS_POLICY_RULE_RECEIVE:
1715 rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
1716 /* allow rules default to TRUE (only requested replies allowed)
1717 + * check rules default to TRUE (only requested replies are checked)
1718 * deny rules default to FALSE (only unrequested replies denied)
1720 - rule->d.receive.requested_reply = rule->allow;
1721 + rule->d.receive.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
1723 case BUS_POLICY_RULE_OWN:
1725 @@ -117,7 +119,8 @@ bus_policy_rule_unref (BusPolicyRule *rule)
1726 case BUS_POLICY_RULE_GROUP:
1731 + dbus_free (rule->privilege);
1735 @@ -427,7 +430,10 @@ list_allows_user (dbus_bool_t def,
1739 - allowed = rule->allow;
1740 + /* We don't intend to support <check user="..." /> and <check group="..." />
1741 + rules. They are treated like deny.
1743 + allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
1747 @@ -862,18 +868,23 @@ bus_client_policy_append_rule (BusClientPolicy *policy,
1752 -bus_client_policy_check_can_send (BusClientPolicy *policy,
1753 - BusRegistry *registry,
1754 - dbus_bool_t requested_reply,
1755 - DBusConnection *receiver,
1756 - DBusMessage *message,
1757 - dbus_int32_t *toggles,
1760 +bus_client_policy_check_can_send (DBusConnection *sender,
1761 + BusClientPolicy *policy,
1762 + BusRegistry *registry,
1763 + dbus_bool_t requested_reply,
1764 + DBusConnection *addressed_recipient,
1765 + DBusConnection *receiver,
1766 + DBusMessage *message,
1767 + dbus_int32_t *toggles,
1769 + const char **privilege_param,
1770 + BusDeferredMessage **deferred_message)
1773 - dbus_bool_t allowed;
1776 + const char *privilege;
1778 /* policy->rules is in the order the rules appeared
1779 * in the config file, i.e. last rule that applies wins
1781 @@ -881,7 +892,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1782 _dbus_verbose (" (policy) checking send rules\n");
1786 + result = BUS_RESULT_FALSE;
1787 link = _dbus_list_get_first_link (&policy->rules);
1788 while (link != NULL)
1790 @@ -912,13 +923,14 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1791 /* If it's a reply, the requested_reply flag kicks in */
1792 if (dbus_message_get_reply_serial (message) != 0)
1794 - /* for allow, requested_reply=true means the rule applies
1795 - * only when reply was requested. requested_reply=false means
1797 + /* for allow or check requested_reply=true means the rule applies
1798 + * only when reply was requested. requested_reply=false means the
1799 + * rule always applies
1801 - if (!requested_reply && rule->allow && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
1802 + if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
1804 - _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
1805 + _dbus_verbose (" (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
1806 + rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
1810 @@ -926,7 +938,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1811 * when the reply was not requested. requested_reply=true means the
1812 * rule always applies.
1814 - if (requested_reply && !rule->allow && !rule->d.send.requested_reply)
1815 + if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.send.requested_reply)
1817 _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n");
1819 @@ -949,13 +961,15 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1820 /* The interface is optional in messages. For allow rules, if the message
1821 * has no interface we want to skip the rule (and thus not allow);
1822 * for deny rules, if the message has no interface we want to use the
1823 - * rule (and thus deny).
1824 + * rule (and thus deny). Check rules are meant to be used like allow
1825 + * rules (they can grant access, but not remove it), so we treat it like
1828 dbus_bool_t no_interface;
1830 no_interface = dbus_message_get_interface (message) == NULL;
1832 - if ((no_interface && rule->allow) ||
1833 + if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
1835 strcmp (dbus_message_get_interface (message),
1836 rule->d.send.interface) != 0))
1837 @@ -1029,33 +1043,63 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1841 - allowed = rule->allow;
1842 + switch (rule->access)
1844 + case BUS_POLICY_RULE_ACCESS_ALLOW:
1845 + result = BUS_RESULT_TRUE;
1847 + case BUS_POLICY_RULE_ACCESS_DENY:
1848 + result = BUS_RESULT_FALSE;
1850 + case BUS_POLICY_RULE_ACCESS_CHECK:
1851 + result = BUS_RESULT_LATER;
1852 + privilege = rule->privilege;
1856 *log = rule->d.send.log;
1859 - _dbus_verbose (" (policy) used rule, allow now = %d\n",
1861 + _dbus_verbose (" (policy) used rule, result now = %d\n",
1862 + (int)(intptr_t)result);
1866 + if (result == BUS_RESULT_LATER)
1868 + BusContext *context = bus_connection_get_context(sender);
1869 + BusCheck *check = bus_context_get_check(context);
1871 + result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
1872 + privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
1877 + if (privilege_param != NULL)
1878 + *privilege_param = privilege;
1883 /* See docs on what the args mean on bus_context_check_security_policy()
1887 -bus_client_policy_check_can_receive (BusClientPolicy *policy,
1888 - BusRegistry *registry,
1889 - dbus_bool_t requested_reply,
1890 - DBusConnection *sender,
1891 - DBusConnection *addressed_recipient,
1892 - DBusConnection *proposed_recipient,
1893 - DBusMessage *message,
1894 - dbus_int32_t *toggles)
1896 +bus_client_policy_check_can_receive (BusClientPolicy *policy,
1897 + BusRegistry *registry,
1898 + dbus_bool_t requested_reply,
1899 + DBusConnection *sender,
1900 + DBusConnection *addressed_recipient,
1901 + DBusConnection *proposed_recipient,
1902 + DBusMessage *message,
1903 + dbus_int32_t *toggles,
1904 + const char **privilege_param,
1905 + BusDeferredMessage **deferred_message)
1908 - dbus_bool_t allowed;
1909 dbus_bool_t eavesdropping;
1911 + const char *privilege;
1914 addressed_recipient != proposed_recipient &&
1915 @@ -1068,7 +1112,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1916 _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
1920 + result = BUS_RESULT_FALSE;
1921 link = _dbus_list_get_first_link (&policy->rules);
1922 while (link != NULL)
1924 @@ -1091,19 +1135,21 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1928 - /* for allow, eavesdrop=false means the rule doesn't apply when
1929 - * eavesdropping. eavesdrop=true means always allow.
1931 + /* for allow or check, eavesdrop=false means the rule doesn't apply when
1932 + * eavesdropping. eavesdrop=true means the rule always applies
1934 - if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop)
1935 + if (eavesdropping && rule->access != BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.eavesdrop)
1937 - _dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n");
1938 + _dbus_verbose (" (policy) skipping %s rule since it doesn't apply to eavesdropping\n",
1939 + rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
1943 /* for deny, eavesdrop=true means the rule applies only when
1944 * eavesdropping; eavesdrop=false means always deny.
1946 - if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop)
1947 + if (!eavesdropping && rule->access == BUS_POLICY_RULE_ACCESS_DENY && rule->d.receive.eavesdrop)
1949 _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n");
1951 @@ -1112,13 +1158,14 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1952 /* If it's a reply, the requested_reply flag kicks in */
1953 if (dbus_message_get_reply_serial (message) != 0)
1955 - /* for allow, requested_reply=true means the rule applies
1956 - * only when reply was requested. requested_reply=false means
1958 + /* for allow or check requested_reply=true means the rule applies
1959 + * only when reply was requested. requested_reply=false means the
1960 + * rule always applies
1962 - if (!requested_reply && rule->allow && rule->d.receive.requested_reply && !rule->d.receive.eavesdrop)
1963 + if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
1965 - _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
1966 + _dbus_verbose (" (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
1967 + rule->access == BUS_POLICY_RULE_ACCESS_DENY ? "allow" : "deny");
1971 @@ -1126,7 +1173,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1972 * when the reply was not requested. requested_reply=true means the
1973 * rule always applies.
1975 - if (requested_reply && !rule->allow && !rule->d.receive.requested_reply)
1976 + if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.requested_reply)
1978 _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n");
1980 @@ -1149,13 +1196,13 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1981 /* The interface is optional in messages. For allow rules, if the message
1982 * has no interface we want to skip the rule (and thus not allow);
1983 * for deny rules, if the message has no interface we want to use the
1984 - * rule (and thus deny).
1985 + * rule (and thus deny). Check rules are treated like allow rules.
1987 dbus_bool_t no_interface;
1989 no_interface = dbus_message_get_interface (message) == NULL;
1991 - if ((no_interface && rule->allow) ||
1992 + if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
1994 strcmp (dbus_message_get_interface (message),
1995 rule->d.receive.interface) != 0))
1996 @@ -1230,14 +1277,42 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
2000 - allowed = rule->allow;
2001 + switch (rule->access)
2003 + case BUS_POLICY_RULE_ACCESS_ALLOW:
2004 + result = BUS_RESULT_TRUE;
2006 + case BUS_POLICY_RULE_ACCESS_DENY:
2007 + result = BUS_RESULT_FALSE;
2009 + case BUS_POLICY_RULE_ACCESS_CHECK:
2010 + result = BUS_RESULT_LATER;
2011 + privilege = rule->privilege;
2017 - _dbus_verbose (" (policy) used rule, allow now = %d\n",
2019 + _dbus_verbose (" (policy) used rule, result now = %d\n",
2020 + (int)(intptr_t)result);
2025 + if (result == BUS_RESULT_LATER)
2027 + BusContext *context = bus_connection_get_context(proposed_recipient);
2028 + BusCheck *check = bus_context_get_check(context);
2030 + result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
2031 + privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
2036 + if (privilege_param != NULL)
2037 + *privilege_param = privilege;
2043 @@ -1289,7 +1364,7 @@ bus_rules_check_can_own (DBusList *rules,
2047 - allowed = rule->allow;
2048 + allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
2052 diff --git a/bus/policy.h b/bus/policy.h
2053 index d1d3e72b..e9f193af 100644
2056 @@ -39,6 +39,14 @@ typedef enum
2057 BUS_POLICY_RULE_GROUP
2058 } BusPolicyRuleType;
2062 + BUS_POLICY_RULE_ACCESS_DENY,
2063 + BUS_POLICY_RULE_ACCESS_ALLOW,
2064 + /** runtime check resulting in allow or deny */
2065 + BUS_POLICY_RULE_ACCESS_CHECK
2066 +} BusPolicyRuleAccess;
2068 /** determines whether the rule affects a connection, or some global item */
2069 #define BUS_POLICY_RULE_IS_PER_CLIENT(rule) (!((rule)->type == BUS_POLICY_RULE_USER || \
2070 (rule)->type == BUS_POLICY_RULE_GROUP))
2071 @@ -49,8 +57,9 @@ struct BusPolicyRule
2073 BusPolicyRuleType type;
2075 - unsigned int allow : 1; /**< #TRUE if this allows, #FALSE if it denies */
2077 + unsigned int access : 2; /**< BusPolicyRuleAccess */
2078 + char *privilege; /**< for BUS_POLICY_RULE_ACCESS_CHECK */
2083 @@ -106,7 +115,7 @@ struct BusPolicyRule
2086 BusPolicyRule* bus_policy_rule_new (BusPolicyRuleType type,
2087 - dbus_bool_t allow);
2088 + BusPolicyRuleAccess access);
2089 BusPolicyRule* bus_policy_rule_ref (BusPolicyRule *rule);
2090 void bus_policy_rule_unref (BusPolicyRule *rule);
2092 @@ -140,21 +149,27 @@ dbus_bool_t bus_policy_merge (BusPolicy *policy,
2093 BusClientPolicy* bus_client_policy_new (void);
2094 BusClientPolicy* bus_client_policy_ref (BusClientPolicy *policy);
2095 void bus_client_policy_unref (BusClientPolicy *policy);
2096 -dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy,
2097 - BusRegistry *registry,
2098 - dbus_bool_t requested_reply,
2099 - DBusConnection *receiver,
2100 - DBusMessage *message,
2101 - dbus_int32_t *toggles,
2102 - dbus_bool_t *log);
2103 -dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy,
2104 - BusRegistry *registry,
2105 - dbus_bool_t requested_reply,
2106 - DBusConnection *sender,
2107 - DBusConnection *addressed_recipient,
2108 - DBusConnection *proposed_recipient,
2109 - DBusMessage *message,
2110 - dbus_int32_t *toggles);
2111 +BusResult bus_client_policy_check_can_send (DBusConnection *sender,
2112 + BusClientPolicy *policy,
2113 + BusRegistry *registry,
2114 + dbus_bool_t requested_reply,
2115 + DBusConnection *addressed_recipient,
2116 + DBusConnection *receiver,
2117 + DBusMessage *message,
2118 + dbus_int32_t *toggles,
2120 + const char **privilege_param,
2121 + BusDeferredMessage **deferred_message);
2122 +BusResult bus_client_policy_check_can_receive (BusClientPolicy *policy,
2123 + BusRegistry *registry,
2124 + dbus_bool_t requested_reply,
2125 + DBusConnection *sender,
2126 + DBusConnection *addressed_recipient,
2127 + DBusConnection *proposed_recipient,
2128 + DBusMessage *message,
2129 + dbus_int32_t *toggles,
2130 + const char **privilege_param,
2131 + BusDeferredMessage **deferred_message);
2132 dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy,
2133 const DBusString *service_name);
2134 dbus_bool_t bus_client_policy_append_rule (BusClientPolicy *policy,
2135 diff --git a/configure.ac b/configure.ac
2136 index 71e3515c..f3a2ffc1 100644
2139 @@ -1873,6 +1873,17 @@ AC_ARG_ENABLE([user-session],
2140 AM_CONDITIONAL([DBUS_ENABLE_USER_SESSION],
2141 [test "x$enable_user_session" = xyes])
2143 +#enable cynara integration
2144 +AC_ARG_ENABLE([cynara], [AS_HELP_STRING([--enable-cynara], [enable Cynara integration])], [], [enable_cynara=no])
2145 +if test "x$enable_cynara" = xyes; then
2146 + PKG_CHECK_MODULES([CYNARA], [cynara-client-async >= 0.6.0 cynara-session >= 0.6.0],
2147 + [AC_DEFINE([DBUS_ENABLE_CYNARA], [1], [Define to enable Cynara privilege checks in dbus-daemon])],
2148 + [AC_MSG_ERROR([libcynara-client-async and cynara-session are required to enable Cynara integration])])
2151 +AC_SUBST([CYNARA_CFLAGS])
2152 +AC_SUBST([CYNARA_LIBS])
2157 @@ -1952,6 +1963,7 @@ echo "
2158 Building bus stats API: ${enable_stats}
2159 Building SELinux support: ${have_selinux}
2160 Building AppArmor support: ${have_apparmor}
2161 + Building Cynara support: ${enable_cynara}
2162 Building inotify support: ${have_inotify}
2163 Building kqueue support: ${have_kqueue}
2164 Building systemd support: ${have_systemd}
2165 diff --git a/test/Makefile.am b/test/Makefile.am
2166 index 914dd7f2..86882537 100644
2167 --- a/test/Makefile.am
2168 +++ b/test/Makefile.am
2169 @@ -341,6 +341,7 @@ in_data = \
2170 data/valid-config-files/debug-allow-all.conf.in \
2171 data/valid-config-files/finite-timeout.conf.in \
2172 data/valid-config-files/forbidding.conf.in \
2173 + data/valid-config-files/debug-check-some.conf.in \
2174 data/valid-config-files/incoming-limit.conf.in \
2175 data/valid-config-files/multi-user.conf.in \
2176 data/valid-config-files/systemd-activation.conf.in \
2177 diff --git a/test/data/invalid-config-files/badcheck-1.conf b/test/data/invalid-config-files/badcheck-1.conf
2178 new file mode 100644
2179 index 00000000..fad9f502
2181 +++ b/test/data/invalid-config-files/badcheck-1.conf
2183 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2184 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2186 + <user>mybususer</user>
2187 + <listen>unix:path=/foo/bar</listen>
2188 + <policy context="default">
2189 + <allow privilege="foo" send_destination="*"/> <!-- extra privilege="foo" -->
2192 diff --git a/test/data/invalid-config-files/badcheck-2.conf b/test/data/invalid-config-files/badcheck-2.conf
2193 new file mode 100644
2194 index 00000000..63c7ef25
2196 +++ b/test/data/invalid-config-files/badcheck-2.conf
2198 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2199 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2201 + <user>mybususer</user>
2202 + <listen>unix:path=/foo/bar</listen>
2203 + <policy context="default">
2204 + <check send_destination="*"/> <!-- missing privilege="foo" -->
2207 diff --git a/test/data/valid-config-files/check-1.conf b/test/data/valid-config-files/check-1.conf
2208 new file mode 100644
2209 index 00000000..ad714733
2211 +++ b/test/data/valid-config-files/check-1.conf
2213 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2214 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2216 + <user>mybususer</user>
2217 + <listen>unix:path=/foo/bar</listen>
2218 + <policy context="default">
2219 + <check privilege="foo" send_destination="*"/>
2222 diff --git a/test/data/valid-config-files/debug-check-some.conf.in b/test/data/valid-config-files/debug-check-some.conf.in
2223 new file mode 100644
2224 index 00000000..47ee8548
2226 +++ b/test/data/valid-config-files/debug-check-some.conf.in
2228 +<!-- Bus that listens on a debug pipe and doesn't create any restrictions -->
2230 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2231 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2233 + <listen>debug-pipe:name=test-server</listen>
2234 + <listen>@TEST_LISTEN@</listen>
2235 + <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
2236 + <policy context="default">
2237 + <allow send_interface="*"/>
2238 + <allow receive_interface="*"/>
2242 + <deny send_interface="org.freedesktop.TestSuite" send_member="Echo"/>
2243 + <check privilege="foo" send_interface="org.freedesktop.TestSuite" send_member="Echo"/>
2246 diff --git a/tools/dbus-send.c b/tools/dbus-send.c
2247 index 0dc1f5b3..76ddab3f 100644
2248 --- a/tools/dbus-send.c
2249 +++ b/tools/dbus-send.c
2250 @@ -458,7 +458,7 @@ main (int argc, char *argv[])
2254 - int secondary_type;
2255 + int secondary_type = 0;
2257 DBusMessageIter *target_iter;
2258 DBusMessageIter container_iter;