meta-agl: split wireplumber to run in multiple instances
[AGL/meta-agl.git] / meta-app-framework / recipes-core / dbus-cynagora / dbus-cynagora / 0001-Integration-of-Cynara-asynchronous-security-checks.patch
1 From ea4b650366261e4257e4b0fb95e7f48e30ef36f0 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/8] Integration of Cynara asynchronous security checks
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
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.
18
19 Cherry picked from 4dcfb02f17247ff9de966b62182cd2e08f301238
20 by José Bollo.
21
22 Updated for dbus 1.10.20 by Scott Murray and José Bollo
23 Updated for dbus 1.12.16 by José Bollo
24
25 Change-Id: I9bcbce34577e5dc2a3cecf6233a0a2b0e43e1108
26 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
27 Signed-off-by: Scott Murray <scott.murray@konsulko.com>
28 ---
29  bus/Makefile.am                               |   6 +
30  bus/activation.c                              |   5 +-
31  bus/bus.c                                     | 124 ++++--
32  bus/bus.h                                     |  22 +-
33  bus/check.c                                   | 217 ++++++++++
34  bus/check.h                                   |  68 ++++
35  bus/config-parser-common.c                    |   6 +
36  bus/config-parser-common.h                    |   1 +
37  bus/config-parser-trivial.c                   |   2 +
38  bus/config-parser.c                           |  72 +++-
39  bus/connection.c                              |  57 ++-
40  bus/connection.h                              |   4 +
41  bus/cynara.c                                  | 374 ++++++++++++++++++
42  bus/cynara.h                                  |  37 ++
43  bus/dispatch.c                                |  46 ++-
44  bus/driver.h                                  |   2 +
45  bus/policy.c                                  | 195 ++++++---
46  bus/policy.h                                  |  29 +-
47  configure.ac                                  |  12 +
48  test/Makefile.am                              |   1 +
49  .../data/invalid-config-files/badcheck-1.conf |   9 +
50  .../data/invalid-config-files/badcheck-2.conf |   9 +
51  test/data/valid-config-files/check-1.conf     |   9 +
52  .../debug-check-some.conf.in                  |  18 +
53  24 files changed, 1181 insertions(+), 144 deletions(-)
54  create mode 100644 bus/check.c
55  create mode 100644 bus/check.h
56  create mode 100644 bus/cynara.c
57  create mode 100644 bus/cynara.h
58  create mode 100644 test/data/invalid-config-files/badcheck-1.conf
59  create mode 100644 test/data/invalid-config-files/badcheck-2.conf
60  create mode 100644 test/data/valid-config-files/check-1.conf
61  create mode 100644 test/data/valid-config-files/debug-check-some.conf.in
62
63 diff --git a/bus/Makefile.am b/bus/Makefile.am
64 index c917063..2a8a72c 100644
65 --- a/bus/Makefile.am
66 +++ b/bus/Makefile.am
67 @@ -13,6 +13,7 @@ DBUS_BUS_LIBS = \
68         $(THREAD_LIBS) \
69         $(ADT_LIBS) \
70         $(NETWORK_libs) \
71 +       $(CYNARA_LIBS) \
72         $(NULL)
73  
74  DBUS_LAUNCHER_LIBS = \
75 @@ -30,6 +31,7 @@ AM_CPPFLAGS = \
76         $(APPARMOR_CFLAGS) \
77         -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \
78         -DDBUS_COMPILATION \
79 +       $(CYNARA_CFLAGS) \
80         $(NULL)
81  
82  # if assertions are enabled, improve backtraces
83 @@ -90,6 +92,8 @@ BUS_SOURCES=                                  \
84         audit.h                                 \
85         bus.c                                   \
86         bus.h                                   \
87 +       check.c                                 \
88 +       check.h                                 \
89         config-loader-expat.c                   \
90         config-parser.c                         \
91         config-parser.h                         \
92 @@ -97,6 +101,8 @@ BUS_SOURCES=                                 \
93         config-parser-common.h                  \
94         connection.c                            \
95         connection.h                            \
96 +       cynara.c                                \
97 +       cynara.h                                \
98         desktop-file.c                          \
99         desktop-file.h                          \
100         $(DIR_WATCH_SOURCE)                     \
101 diff --git a/bus/activation.c b/bus/activation.c
102 index 99404b9..f9c6c62 100644
103 --- a/bus/activation.c
104 +++ b/bus/activation.c
105 @@ -1789,14 +1789,15 @@ bus_activation_activate_service (BusActivation  *activation,
106  
107    if (auto_activation &&
108        entry != NULL &&
109 -      !bus_context_check_security_policy (activation->context,
110 +      BUS_RESULT_TRUE != bus_context_check_security_policy (activation->context,
111          transaction,
112          connection, /* sender */
113          NULL, /* addressed recipient */
114          NULL, /* proposed recipient */
115          activation_message,
116          entry,
117 -        error))
118 +        error,
119 +        NULL))
120      {
121        _DBUS_ASSERT_ERROR_IS_SET (error);
122        _dbus_verbose ("activation not authorized: %s: %s\n",
123 diff --git a/bus/bus.c b/bus/bus.c
124 index 2ad8e78..6fc45d0 100644
125 --- a/bus/bus.c
126 +++ b/bus/bus.c
127 @@ -38,6 +38,7 @@
128  #include "apparmor.h"
129  #include "audit.h"
130  #include "dir-watch.h"
131 +#include "check.h"
132  #include <dbus/dbus-auth.h>
133  #include <dbus/dbus-list.h>
134  #include <dbus/dbus-hash.h>
135 @@ -67,6 +68,7 @@ struct BusContext
136    BusRegistry *registry;
137    BusPolicy *policy;
138    BusMatchmaker *matchmaker;
139 +  BusCheck *check;
140    BusLimits limits;
141    DBusRLimit *initial_fd_limit;
142    unsigned int fork : 1;
143 @@ -1003,6 +1005,10 @@ bus_context_new (const DBusString *config_file,
144        parser = NULL;
145      }
146  
147 +  context->check = bus_check_new(context, error);
148 +  if (context->check == NULL)
149 +      goto failed;
150 +
151    dbus_server_free_data_slot (&server_data_slot);
152  
153    return context;
154 @@ -1127,6 +1133,12 @@ bus_context_unref (BusContext *context)
155  
156        bus_context_shutdown (context);
157  
158 +      if (context->check)
159 +        {
160 +          bus_check_unref(context->check);
161 +          context->check = NULL;
162 +        }
163 +
164        if (context->connections)
165          {
166            bus_connections_unref (context->connections);
167 @@ -1256,6 +1268,12 @@ bus_context_get_loop (BusContext *context)
168    return context->loop;
169  }
170  
171 +BusCheck*
172 +bus_context_get_check (BusContext *context)
173 +{
174 +  return context->check;
175 +}
176 +
177  dbus_bool_t
178  bus_context_allow_unix_user (BusContext   *context,
179                               unsigned long uid)
180 @@ -1451,6 +1469,7 @@ complain_about_message (BusContext     *context,
181                          DBusConnection *proposed_recipient,
182                          dbus_bool_t     requested_reply,
183                          dbus_bool_t     log,
184 +                        const char     *privilege,
185                          DBusError      *error)
186  {
187    DBusError stack_error = DBUS_ERROR_INIT;
188 @@ -1480,7 +1499,8 @@ complain_about_message (BusContext     *context,
189    dbus_set_error (&stack_error, error_name,
190        "%s, %d matched rules; type=\"%s\", sender=\"%s\" (%s) "
191        "interface=\"%s\" member=\"%s\" error name=\"%s\" "
192 -      "requested_reply=\"%d\" destination=\"%s\" (%s)",
193 +      "requested_reply=\"%d\" destination=\"%s\" (%s) "
194 +      "privilege=\"%s\"",
195        complaint,
196        matched_rules,
197        dbus_message_type_to_string (dbus_message_get_type (message)),
198 @@ -1491,7 +1511,8 @@ complain_about_message (BusContext     *context,
199        nonnull (dbus_message_get_error_name (message), "(unset)"),
200        requested_reply,
201        nonnull (dbus_message_get_destination (message), DBUS_SERVICE_DBUS),
202 -      proposed_recipient_loginfo);
203 +      proposed_recipient_loginfo,
204 +      nonnull (privilege, "(n/a)"));
205  
206    /* If we hit OOM while setting the error, this will syslog "out of memory"
207     * which is itself an indication that something is seriously wrong */
208 @@ -1519,7 +1540,7 @@ complain_about_message (BusContext     *context,
209   * NULL for addressed_recipient may mean the bus driver, or may mean
210   * no destination was specified in the message (e.g. a signal).
211   */
212 -dbus_bool_t
213 +BusResult
214  bus_context_check_security_policy (BusContext     *context,
215                                     BusTransaction *transaction,
216                                     DBusConnection *sender,
217 @@ -1527,7 +1548,8 @@ bus_context_check_security_policy (BusContext     *context,
218                                     DBusConnection *proposed_recipient,
219                                     DBusMessage    *message,
220                                     BusActivationEntry *activation_entry,
221 -                                   DBusError      *error)
222 +                                   DBusError      *error,
223 +                                   BusDeferredMessage **deferred_message)
224  {
225    const char *src, *dest;
226    BusClientPolicy *sender_policy;
227 @@ -1536,6 +1558,7 @@ bus_context_check_security_policy (BusContext     *context,
228    dbus_bool_t log;
229    int type;
230    dbus_bool_t requested_reply;
231 +  const char *privilege;
232  
233    type = dbus_message_get_type (message);
234    src = dbus_message_get_sender (message);
235 @@ -1565,7 +1588,7 @@ bus_context_check_security_policy (BusContext     *context,
236        dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
237                        "Message bus will not accept messages of unknown type\n");
238  
239 -      return FALSE;
240 +      return BUS_RESULT_FALSE;
241      }
242  
243    requested_reply = FALSE;
244 @@ -1595,7 +1618,7 @@ bus_context_check_security_policy (BusContext     *context,
245                    if (dbus_error_is_set (&error2))
246                      {
247                        dbus_move_error (&error2, error);
248 -                      return FALSE;
249 +                      return BUS_RESULT_FALSE;
250                      }
251                  }
252              }
253 @@ -1624,11 +1647,11 @@ bus_context_check_security_policy (BusContext     *context,
254                complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
255                    "An SELinux policy prevents this sender from sending this "
256                    "message to this recipient",
257 -                  0, message, sender, proposed_recipient, FALSE, FALSE, error);
258 +                  0, message, sender, proposed_recipient, FALSE, FALSE, NULL, error);
259                _dbus_verbose ("SELinux security check denying send to service\n");
260              }
261  
262 -          return FALSE;
263 +          return BUS_RESULT_FALSE;
264          }
265  
266        /* next verify AppArmor access controls.  If allowed then
267 @@ -1646,7 +1669,7 @@ bus_context_check_security_policy (BusContext     *context,
268                                       src ? src : DBUS_SERVICE_DBUS,
269                                       activation_entry,
270                                       error))
271 -        return FALSE;
272 +        return BUS_RESULT_FALSE;
273  
274        if (!bus_connection_is_active (sender))
275          {
276 @@ -1660,7 +1683,7 @@ bus_context_check_security_policy (BusContext     *context,
277              {
278                _dbus_verbose ("security check allowing %s message\n",
279                               "Hello");
280 -              return TRUE;
281 +              return BUS_RESULT_TRUE;
282              }
283            else
284              {
285 @@ -1671,7 +1694,7 @@ bus_context_check_security_policy (BusContext     *context,
286                                "Client tried to send a message other than %s without being registered",
287                                "Hello");
288  
289 -              return FALSE;
290 +              return BUS_RESULT_FALSE;
291              }
292          }
293      }
294 @@ -1720,20 +1743,29 @@ bus_context_check_security_policy (BusContext     *context,
295                  (proposed_recipient == NULL && recipient_policy == NULL));
296  
297    log = FALSE;
298 -  if (sender_policy &&
299 -      !bus_client_policy_check_can_send (sender_policy,
300 -                                         context->registry,
301 -                                         requested_reply,
302 -                                         proposed_recipient,
303 -                                         message, &toggles, &log))
304 -    {
305 -      complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
306 -          "Rejected send message", toggles,
307 -          message, sender, proposed_recipient, requested_reply,
308 -          (addressed_recipient == proposed_recipient), error);
309 -      _dbus_verbose ("security policy disallowing message due to sender policy\n");
310 -      return FALSE;
311 -    }
312 +  if (sender_policy)
313 +    {
314 +      BusResult res = bus_client_policy_check_can_send (sender,
315 +                                                        sender_policy,
316 +                                                        context->registry,
317 +                                                        requested_reply,
318 +                                                        addressed_recipient,
319 +                                                        proposed_recipient,
320 +                                                        message, &toggles, &log, &privilege,
321 +                                                        deferred_message);
322 +      if (res == BUS_RESULT_FALSE)
323 +        {
324 +          complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
325 +                                  "Rejected send message", toggles,
326 +                                  message, sender, proposed_recipient, requested_reply,
327 +                                  (addressed_recipient == proposed_recipient), privilege,
328 +                                  error);
329 +          _dbus_verbose ("security policy disallowing message due to sender policy\n");
330 +          return BUS_RESULT_FALSE;
331 +        }
332 +      else if (res == BUS_RESULT_LATER)
333 +        return BUS_RESULT_LATER;
334 +  }
335  
336    if (log)
337      {
338 @@ -1742,23 +1774,29 @@ bus_context_check_security_policy (BusContext     *context,
339        complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
340            "Would reject message", toggles,
341            message, sender, proposed_recipient, requested_reply,
342 -          TRUE, NULL);
343 +          TRUE, privilege, NULL);
344      }
345  
346 -  if (recipient_policy &&
347 -      !bus_client_policy_check_can_receive (recipient_policy,
348 -                                            context->registry,
349 -                                            requested_reply,
350 -                                            sender,
351 -                                            addressed_recipient, proposed_recipient,
352 -                                            message, &toggles))
353 +  if (recipient_policy)
354      {
355 -      complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
356 -          "Rejected receive message", toggles,
357 -          message, sender, proposed_recipient, requested_reply,
358 -          (addressed_recipient == proposed_recipient), error);
359 -      _dbus_verbose ("security policy disallowing message due to recipient policy\n");
360 -      return FALSE;
361 +      BusResult res;
362 +      res = bus_client_policy_check_can_receive (recipient_policy,
363 +                                                 context->registry,
364 +                                                 requested_reply,
365 +                                                 sender,
366 +                                                 addressed_recipient, proposed_recipient,
367 +                                                 message, &toggles, &privilege, deferred_message);
368 +      if (res == BUS_RESULT_FALSE)
369 +        {
370 +          complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected receive message",
371 +              toggles, message, sender, proposed_recipient, requested_reply,
372 +            (addressed_recipient == proposed_recipient), privilege, error);
373 +          _dbus_verbose(
374 +            "security policy disallowing message due to recipient policy\n");
375 +          return BUS_RESULT_FALSE;
376 +        }
377 +      else if (res == BUS_RESULT_LATER)
378 +        return BUS_RESULT_LATER;
379      }
380  
381    /* See if limits on size have been exceeded */
382 @@ -1768,10 +1806,10 @@ bus_context_check_security_policy (BusContext     *context,
383      {
384        complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
385            "Rejected: destination has a full message queue",
386 -          0, message, sender, proposed_recipient, requested_reply, TRUE,
387 +          0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
388            error);
389        _dbus_verbose ("security policy disallowing message due to full message queue\n");
390 -      return FALSE;
391 +      return BUS_RESULT_FALSE;
392      }
393  
394    /* Record that we will allow a reply here in the future (don't
395 @@ -1792,11 +1830,11 @@ bus_context_check_security_policy (BusContext     *context,
396                                       message, error))
397      {
398        _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
399 -      return FALSE;
400 +      return BUS_RESULT_FALSE;
401      }
402  
403    _dbus_verbose ("security policy allowing message\n");
404 -  return TRUE;
405 +  return BUS_RESULT_TRUE;
406  }
407  
408  void
409 diff --git a/bus/bus.h b/bus/bus.h
410 index 2e0de82..82c32c8 100644
411 --- a/bus/bus.h
412 +++ b/bus/bus.h
413 @@ -45,6 +45,22 @@ typedef struct BusTransaction   BusTransaction;
414  typedef struct BusMatchmaker    BusMatchmaker;
415  typedef struct BusMatchRule     BusMatchRule;
416  typedef struct BusActivationEntry BusActivationEntry;
417 +typedef struct BusCheck         BusCheck;
418 +typedef struct BusDeferredMessage BusDeferredMessage;
419 +typedef struct BusCynara        BusCynara;
420 +
421 +/**
422 + * BusResult is defined as a pointer to a dummy structure to allow detection of type mismatches.
423 + * The disadvantage of such solution is that now BusResult variables cannot be used in switch
424 + * statement.
425 + * Additionally, BUS_RESULT_TRUE is defined as 0 instead of 1 to help detect type mismatches
426 + * at runtime.
427 + */
428 +typedef const struct BusResultStruct { int dummy; } *BusResult;
429 +
430 +static const BusResult BUS_RESULT_TRUE  = (BusResult)0x0;
431 +static const BusResult BUS_RESULT_FALSE = (BusResult)0x1;
432 +static const BusResult BUS_RESULT_LATER = (BusResult)0x2;
433  
434  typedef struct
435  {
436 @@ -101,6 +117,7 @@ BusConnections*   bus_context_get_connections                    (BusContext
437  BusActivation*    bus_context_get_activation                     (BusContext       *context);
438  BusMatchmaker*    bus_context_get_matchmaker                     (BusContext       *context);
439  DBusLoop*         bus_context_get_loop                           (BusContext       *context);
440 +BusCheck *        bus_context_get_check                          (BusContext       *context);
441  dbus_bool_t       bus_context_allow_unix_user                    (BusContext       *context,
442                                                                    unsigned long     uid);
443  dbus_bool_t       bus_context_allow_windows_user                 (BusContext       *context,
444 @@ -136,14 +153,15 @@ void              bus_context_log_and_set_error                  (BusContext
445                                                                    const char       *name,
446                                                                    const char       *msg,
447                                                                    ...) _DBUS_GNUC_PRINTF (5, 6);
448 -dbus_bool_t       bus_context_check_security_policy              (BusContext       *context,
449 +BusResult         bus_context_check_security_policy              (BusContext       *context,
450                                                                    BusTransaction   *transaction,
451                                                                    DBusConnection   *sender,
452                                                                    DBusConnection   *addressed_recipient,
453                                                                    DBusConnection   *proposed_recipient,
454                                                                    DBusMessage      *message,
455                                                                    BusActivationEntry *activation_entry,
456 -                                                                  DBusError        *error);
457 +                                                                  DBusError        *error,
458 +                                                                  BusDeferredMessage **deferred_message);
459  void              bus_context_check_all_watches                  (BusContext       *context);
460  
461  #endif /* BUS_BUS_H */
462 diff --git a/bus/check.c b/bus/check.c
463 new file mode 100644
464 index 0000000..5b72d31
465 --- /dev/null
466 +++ b/bus/check.c
467 @@ -0,0 +1,217 @@
468 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
469 +/* check.c  Bus security policy runtime check
470 + *
471 + * Copyright (C) 2014  Intel, Inc.
472 + * Copyright (c) 2014  Samsung Electronics, Ltd.
473 + *
474 + * Licensed under the Academic Free License version 2.1
475 + *
476 + * This program is free software; you can redistribute it and/or modify
477 + * it under the terms of the GNU General Public License as published by
478 + * the Free Software Foundation; either version 2 of the License, or
479 + * (at your option) any later version.
480 + *
481 + * This program is distributed in the hope that it will be useful,
482 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
483 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
484 + * GNU General Public License for more details.
485 + *
486 + * You should have received a copy of the GNU General Public License
487 + * along with this program; if not, write to the Free Software
488 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
489 + *
490 + */
491 +
492 +#include <config.h>
493 +#include "check.h"
494 +#include "connection.h"
495 +#include "dispatch.h"
496 +#include "cynara.h"
497 +#include "utils.h"
498 +#include <dbus/dbus-connection-internal.h>
499 +#include <dbus/dbus-message-internal.h>
500 +#include <dbus/dbus-internals.h>
501 +
502 +
503 +typedef struct BusCheck
504 +{
505 +  int refcount;
506 +
507 +  BusContext *context;
508 +  BusCynara *cynara;
509 +} BusCheck;
510 +
511 +typedef struct BusDeferredMessage
512 +{
513 +  int refcount;
514 +
515 +  DBusMessage *message;
516 +  DBusConnection *sender;
517 +  DBusConnection *proposed_recipient;
518 +  DBusConnection *addressed_recipient;
519 +  dbus_bool_t full_dispatch;
520 +  BusDeferredMessageStatus status;
521 +  BusResult response;
522 +  BusCheckResponseFunc response_callback;
523 +} BusDeferredMessage;
524 +
525 +BusCheck *
526 +bus_check_new (BusContext *context, DBusError *error)
527 +{
528 +  BusCheck *check;
529 +
530 +  check = dbus_new(BusCheck, 1);
531 +  if (check == NULL)
532 +    {
533 +      BUS_SET_OOM(error);
534 +      return NULL;
535 +    }
536 +
537 +  check->refcount = 1;
538 +  check->context = context;
539 +  check->cynara = bus_cynara_new(check, error);
540 +  if (dbus_error_is_set(error))
541 +    {
542 +      dbus_free(check);
543 +      return NULL;
544 +    }
545 +
546 +  return check;
547 +}
548 +
549 +BusCheck *
550 +bus_check_ref (BusCheck *check)
551 +{
552 +  _dbus_assert (check->refcount > 0);
553 +  check->refcount += 1;
554 +
555 +  return check;
556 +}
557 +
558 +void
559 +bus_check_unref (BusCheck *check)
560 +{
561 +  _dbus_assert (check->refcount > 0);
562 +
563 +  check->refcount -= 1;
564 +
565 +  if (check->refcount == 0)
566 +    {
567 +      bus_cynara_unref(check->cynara);
568 +      dbus_free(check);
569 +    }
570 +}
571 +
572 +BusContext *
573 +bus_check_get_context (BusCheck *check)
574 +{
575 +  return check->context;
576 +}
577 +
578 +BusCynara *
579 +bus_check_get_cynara (BusCheck *check)
580 +{
581 +  return check->cynara;
582 +}
583 +
584 +BusResult
585 +bus_check_privilege (BusCheck *check,
586 +                     DBusMessage *message,
587 +                     DBusConnection *sender,
588 +                     DBusConnection *addressed_recipient,
589 +                     DBusConnection *proposed_recipient,
590 +                     const char *privilege,
591 +                     BusDeferredMessageStatus check_type,
592 +                     BusDeferredMessage **deferred_message)
593 +{
594 +  BusResult result = BUS_RESULT_FALSE;
595 +#ifdef DBUS_ENABLE_CYNARA
596 +  BusCynara *cynara;
597 +#endif
598 +  DBusConnection *connection;
599 +
600 +  connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
601 +
602 +  if (!dbus_connection_get_is_connected(connection))
603 +    {
604 +      return BUS_RESULT_FALSE;
605 +    }
606 +
607 +  /* ask policy checkers */
608 +#ifdef DBUS_ENABLE_CYNARA
609 +  cynara = bus_check_get_cynara(check);
610 +  result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
611 +      proposed_recipient, privilege, check_type, deferred_message);
612 +#endif
613 +
614 +  if (result == BUS_RESULT_LATER && deferred_message != NULL)
615 +    {
616 +      (*deferred_message)->status |= check_type;
617 +    }
618 +  return result;
619 +}
620 +
621 +BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
622 +                                              DBusConnection *sender,
623 +                                              DBusConnection *addressed_recipient,
624 +                                              DBusConnection *proposed_recipient,
625 +                                              BusResult response)
626 +{
627 +  BusDeferredMessage *deferred_message;
628 +
629 +  deferred_message = dbus_new(BusDeferredMessage, 1);
630 +  if (deferred_message == NULL)
631 +    {
632 +      return NULL;
633 +    }
634 +
635 +  deferred_message->refcount = 1;
636 +  deferred_message->sender = sender != NULL ? dbus_connection_ref(sender) : NULL;
637 +  deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
638 +  deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
639 +  deferred_message->message = dbus_message_ref(message);
640 +  deferred_message->response = response;
641 +  deferred_message->status = 0;
642 +  deferred_message->full_dispatch = FALSE;
643 +  deferred_message->response_callback = NULL;
644 +
645 +  return deferred_message;
646 +}
647 +
648 +BusDeferredMessage *
649 +bus_deferred_message_ref (BusDeferredMessage *deferred_message)
650 +{
651 +  _dbus_assert (deferred_message->refcount > 0);
652 +  deferred_message->refcount += 1;
653 +  return deferred_message;
654 +}
655 +
656 +void
657 +bus_deferred_message_unref (BusDeferredMessage *deferred_message)
658 +{
659 +  _dbus_assert (deferred_message->refcount > 0);
660 +
661 +  deferred_message->refcount -= 1;
662 +
663 +   if (deferred_message->refcount == 0)
664 +     {
665 +       dbus_message_unref(deferred_message->message);
666 +       if (deferred_message->sender != NULL)
667 +           dbus_connection_unref(deferred_message->sender);
668 +       if (deferred_message->addressed_recipient != NULL)
669 +           dbus_connection_unref(deferred_message->addressed_recipient);
670 +       if (deferred_message->proposed_recipient != NULL)
671 +           dbus_connection_unref(deferred_message->proposed_recipient);
672 +       dbus_free(deferred_message);
673 +     }
674 +}
675 +
676 +void
677 +bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
678 +                                        BusResult result)
679 +{
680 +  if (deferred_message->response_callback != NULL)
681 +    {
682 +      deferred_message->response_callback(deferred_message, result);
683 +    }
684 +}
685 diff --git a/bus/check.h b/bus/check.h
686 new file mode 100644
687 index 0000000..c3fcaf9
688 --- /dev/null
689 +++ b/bus/check.h
690 @@ -0,0 +1,68 @@
691 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
692 +/* check.h  Bus security policy runtime check
693 + *
694 + * Copyright (C) 2014  Intel, Inc.
695 + * Copyright (c) 2014  Samsung Electronics, Ltd.
696 + *
697 + * Licensed under the Academic Free License version 2.1
698 + *
699 + * This program is free software; you can redistribute it and/or modify
700 + * it under the terms of the GNU General Public License as published by
701 + * the Free Software Foundation; either version 2 of the License, or
702 + * (at your option) any later version.
703 + *
704 + * This program is distributed in the hope that it will be useful,
705 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
706 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
707 + * GNU General Public License for more details.
708 + *
709 + * You should have received a copy of the GNU General Public License
710 + * along with this program; if not, write to the Free Software
711 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
712 + *
713 + */
714 +
715 +#ifndef BUS_CHECK_H
716 +#define BUS_CHECK_H
717 +
718 +#include "bus.h"
719 +#include "policy.h"
720 +
721 +
722 +typedef void (*BusCheckResponseFunc) (BusDeferredMessage *message,
723 +                                      BusResult result);
724 +
725 +typedef enum {
726 +  BUS_DEFERRED_MESSAGE_CHECK_SEND      = 1 << 0,
727 +  BUS_DEFERRED_MESSAGE_CHECK_RECEIVE   = 1 << 1,
728 +  BUS_DEFERRED_MESSAGE_CHECK_OWN       = 1 << 2,
729 +} BusDeferredMessageStatus;
730 +
731 +
732 +BusCheck   *bus_check_new         (BusContext *context,
733 +                                   DBusError *error);
734 +BusCheck   *bus_check_ref         (BusCheck *check);
735 +void        bus_check_unref       (BusCheck *check);
736 +
737 +BusContext *bus_check_get_context (BusCheck *check);
738 +BusCynara  *bus_check_get_cynara  (BusCheck *check);
739 +BusResult   bus_check_privilege   (BusCheck *check,
740 +                                   DBusMessage *message,
741 +                                   DBusConnection *sender,
742 +                                   DBusConnection *addressed_recipient,
743 +                                   DBusConnection *proposed_recipient,
744 +                                   const char *privilege,
745 +                                   BusDeferredMessageStatus check_type,
746 +                                   BusDeferredMessage **deferred_message);
747 +
748 +BusDeferredMessage *bus_deferred_message_new                (DBusMessage *message,
749 +                                                             DBusConnection *sender,
750 +                                                             DBusConnection *addressed_recipient,
751 +                                                             DBusConnection *proposed_recipient,
752 +                                                             BusResult response);
753 +
754 +BusDeferredMessage *bus_deferred_message_ref                (BusDeferredMessage *deferred_message);
755 +void                bus_deferred_message_unref              (BusDeferredMessage *deferred_message);
756 +void                bus_deferred_message_response_received  (BusDeferredMessage *deferred_message,
757 +                                                             BusResult result);
758 +#endif /* BUS_CHECK_H */
759 diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
760 index c1c4191..e2f253d 100644
761 --- a/bus/config-parser-common.c
762 +++ b/bus/config-parser-common.c
763 @@ -75,6 +75,10 @@ bus_config_parser_element_name_to_type (const char *name)
764      {
765        return ELEMENT_DENY;
766      }
767 +  else if (strcmp (name, "check") == 0)
768 +    {
769 +      return ELEMENT_CHECK;
770 +    }
771    else if (strcmp (name, "servicehelper") == 0)
772      {
773        return ELEMENT_SERVICEHELPER;
774 @@ -159,6 +163,8 @@ bus_config_parser_element_type_to_name (ElementType type)
775        return "allow";
776      case ELEMENT_DENY:
777        return "deny";
778 +    case ELEMENT_CHECK:
779 +      return "check";
780      case ELEMENT_FORK:
781        return "fork";
782      case ELEMENT_PIDFILE:
783 diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
784 index 382a014..9e026d1 100644
785 --- a/bus/config-parser-common.h
786 +++ b/bus/config-parser-common.h
787 @@ -36,6 +36,7 @@ typedef enum
788    ELEMENT_LIMIT,
789    ELEMENT_ALLOW,
790    ELEMENT_DENY,
791 +  ELEMENT_CHECK,
792    ELEMENT_FORK,
793    ELEMENT_PIDFILE,
794    ELEMENT_SERVICEDIR,
795 diff --git a/bus/config-parser-trivial.c b/bus/config-parser-trivial.c
796 index dd65c6d..23dedb4 100644
797 --- a/bus/config-parser-trivial.c
798 +++ b/bus/config-parser-trivial.c
799 @@ -194,6 +194,7 @@ bus_config_parser_start_element (BusConfigParser   *parser,
800      case ELEMENT_POLICY:
801      case ELEMENT_LIMIT:
802      case ELEMENT_ALLOW:
803 +    case ELEMENT_CHECK:
804      case ELEMENT_DENY:
805      case ELEMENT_FORK:
806      case ELEMENT_PIDFILE:
807 @@ -316,6 +317,7 @@ bus_config_parser_content (BusConfigParser   *parser,
808      case ELEMENT_POLICY:
809      case ELEMENT_LIMIT:
810      case ELEMENT_ALLOW:
811 +    case ELEMENT_CHECK:
812      case ELEMENT_DENY:
813      case ELEMENT_FORK:
814      case ELEMENT_PIDFILE:
815 diff --git a/bus/config-parser.c b/bus/config-parser.c
816 index be27d38..7f91469 100644
817 --- a/bus/config-parser.c
818 +++ b/bus/config-parser.c
819 @@ -1318,7 +1318,7 @@ append_rule_from_element (BusConfigParser   *parser,
820                            const char        *element_name,
821                            const char       **attribute_names,
822                            const char       **attribute_values,
823 -                          dbus_bool_t        allow,
824 +                          BusPolicyRuleAccess access,
825                            DBusError         *error)
826  {
827    const char *log;
828 @@ -1360,6 +1360,7 @@ append_rule_from_element (BusConfigParser   *parser,
829    const char *own_prefix;
830    const char *user;
831    const char *group;
832 +  const char *privilege;
833  
834    BusPolicyRule *rule;
835  
836 @@ -1390,6 +1391,7 @@ append_rule_from_element (BusConfigParser   *parser,
837                            "user", &user,
838                            "group", &group,
839                            "log", &log,
840 +                          "privilege", &privilege,
841                            NULL))
842      return FALSE;
843  
844 @@ -1422,6 +1424,7 @@ append_rule_from_element (BusConfigParser   *parser,
845  
846    if (!(any_send_attribute ||
847          any_receive_attribute ||
848 +        privilege ||
849          own || own_prefix || user || group))
850      {
851        dbus_set_error (error, DBUS_ERROR_FAILED,
852 @@ -1438,7 +1441,30 @@ append_rule_from_element (BusConfigParser   *parser,
853                        element_name);
854        return FALSE;
855      }
856 -  
857 +
858 +  if (access == BUS_POLICY_RULE_ACCESS_CHECK)
859 +    {
860 +      if (privilege == NULL || !*privilege)
861 +        {
862 +          dbus_set_error (error, DBUS_ERROR_FAILED,
863 +                          "On element <%s>, you must specify the privilege to be checked.",
864 +                          element_name);
865 +          return FALSE;
866 +        }
867 +    }
868 +  else
869 +    {
870 +      if (privilege != NULL && *privilege)
871 +        {
872 +          dbus_set_error (error, DBUS_ERROR_FAILED,
873 +                          "On element <%s>, privilege %s is used outside of a check rule.",
874 +                          element_name, privilege);
875 +          return FALSE;
876 +        }
877 +      else
878 +        privilege = NULL; /* replace (potentially) empty string with NULL pointer, it wouldn't be used anyway */
879 +    }
880 +
881    /* Allowed combinations of elements are:
882     *
883     *   base, must be all send or all receive:
884 @@ -1589,7 +1615,7 @@ append_rule_from_element (BusConfigParser   *parser,
885                                  error))
886          return FALSE;
887  
888 -      rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); 
889 +      rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, access);
890        if (rule == NULL)
891          goto nomem;
892        
893 @@ -1694,7 +1720,7 @@ append_rule_from_element (BusConfigParser   *parser,
894                                  error))
895          return FALSE;
896  
897 -      rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); 
898 +      rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, access);
899        if (rule == NULL)
900          goto nomem;
901  
902 @@ -1726,7 +1752,7 @@ append_rule_from_element (BusConfigParser   *parser,
903      }
904    else if (own || own_prefix)
905      {
906 -      rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 
907 +      rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, access);
908        if (rule == NULL)
909          goto nomem;
910  
911 @@ -1752,7 +1778,7 @@ append_rule_from_element (BusConfigParser   *parser,
912      {      
913        if (IS_WILDCARD (user))
914          {
915 -          rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
916 +          rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
917            if (rule == NULL)
918              goto nomem;
919  
920 @@ -1767,7 +1793,7 @@ append_rule_from_element (BusConfigParser   *parser,
921        
922            if (_dbus_parse_unix_user_from_config (&username, &uid))
923              {
924 -              rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
925 +              rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
926                if (rule == NULL)
927                  goto nomem;
928  
929 @@ -1784,7 +1810,7 @@ append_rule_from_element (BusConfigParser   *parser,
930      {
931        if (IS_WILDCARD (group))
932          {
933 -          rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
934 +          rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
935            if (rule == NULL)
936              goto nomem;
937  
938 @@ -1799,7 +1825,7 @@ append_rule_from_element (BusConfigParser   *parser,
939            
940            if (_dbus_parse_unix_group_from_config (&groupname, &gid))
941              {
942 -              rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
943 +              rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
944                if (rule == NULL)
945                  goto nomem;
946  
947 @@ -1823,6 +1849,10 @@ append_rule_from_element (BusConfigParser   *parser,
948        _dbus_assert (pe != NULL);
949        _dbus_assert (pe->type == ELEMENT_POLICY);
950  
951 +      rule->privilege = _dbus_strdup (privilege);
952 +      if (privilege && !rule->privilege)
953 +        goto nomem;
954 +
955        switch (pe->d.policy.type)
956          {
957          case POLICY_IGNORED:
958 @@ -1898,7 +1928,7 @@ start_policy_child (BusConfigParser   *parser,
959      {
960        if (!append_rule_from_element (parser, element_name,
961                                       attribute_names, attribute_values,
962 -                                     TRUE, error))
963 +                                     BUS_POLICY_RULE_ACCESS_ALLOW, error))
964          return FALSE;
965        
966        if (push_element (parser, ELEMENT_ALLOW) == NULL)
967 @@ -1913,7 +1943,7 @@ start_policy_child (BusConfigParser   *parser,
968      {
969        if (!append_rule_from_element (parser, element_name,
970                                       attribute_names, attribute_values,
971 -                                     FALSE, error))
972 +                                     BUS_POLICY_RULE_ACCESS_DENY, error))
973          return FALSE;
974        
975        if (push_element (parser, ELEMENT_DENY) == NULL)
976 @@ -1922,6 +1952,21 @@ start_policy_child (BusConfigParser   *parser,
977            return FALSE;
978          }
979        
980 +      return TRUE;
981 +    }
982 +  else if (strcmp (element_name, "check") == 0)
983 +    {
984 +      if (!append_rule_from_element (parser, element_name,
985 +                                     attribute_names, attribute_values,
986 +                                     BUS_POLICY_RULE_ACCESS_CHECK, error))
987 +        return FALSE;
988 +
989 +      if (push_element (parser, ELEMENT_CHECK) == NULL)
990 +        {
991 +          BUS_SET_OOM (error);
992 +          return FALSE;
993 +        }
994 +
995        return TRUE;
996      }
997    else
998 @@ -2284,6 +2329,7 @@ bus_config_parser_end_element (BusConfigParser   *parser,
999      case ELEMENT_POLICY:
1000      case ELEMENT_ALLOW:
1001      case ELEMENT_DENY:
1002 +    case ELEMENT_CHECK:
1003      case ELEMENT_FORK:
1004      case ELEMENT_SYSLOG:
1005      case ELEMENT_KEEP_UMASK:
1006 @@ -2600,6 +2646,7 @@ bus_config_parser_content (BusConfigParser   *parser,
1007      case ELEMENT_POLICY:
1008      case ELEMENT_ALLOW:
1009      case ELEMENT_DENY:
1010 +    case ELEMENT_CHECK:
1011      case ELEMENT_FORK:
1012      case ELEMENT_SYSLOG:
1013      case ELEMENT_KEEP_UMASK:
1014 @@ -3127,6 +3174,8 @@ do_load (const DBusString *full_path,
1015    dbus_error_init (&error);
1016  
1017    parser = bus_config_load (full_path, TRUE, NULL, &error);
1018 +  if (dbus_error_is_set (&error))
1019 +    _dbus_verbose ("Failed to load file: %s\n", error.message);
1020    if (parser == NULL)
1021      {
1022        _DBUS_ASSERT_ERROR_IS_SET (&error);
1023 @@ -3359,6 +3408,7 @@ elements_equal (const Element *a,
1024      case ELEMENT_LISTEN:
1025      case ELEMENT_AUTH:
1026      case ELEMENT_ALLOW:
1027 +    case ELEMENT_CHECK:
1028      case ELEMENT_DENY:
1029      case ELEMENT_FORK:
1030      case ELEMENT_PIDFILE:
1031 diff --git a/bus/connection.c b/bus/connection.c
1032 index 53605fa..b348d42 100644
1033 --- a/bus/connection.c
1034 +++ b/bus/connection.c
1035 @@ -36,6 +36,10 @@
1036  #include <dbus/dbus-timeout.h>
1037  #include <dbus/dbus-connection-internal.h>
1038  #include <dbus/dbus-internals.h>
1039 +#ifdef DBUS_ENABLE_CYNARA
1040 +#include <stdlib.h>
1041 +#include <cynara-session.h>
1042 +#endif
1043  
1044  /* Trim executed commands to this length; we want to keep logs readable */
1045  #define MAX_LOG_COMMAND_LEN 50
1046 @@ -116,6 +120,9 @@ typedef struct
1047  
1048    /** non-NULL if and only if this is a monitor */
1049    DBusList *link_in_monitors;
1050 +#ifdef DBUS_ENABLE_CYNARA
1051 +  char *cynara_session_id;
1052 +#endif
1053  } BusConnectionData;
1054  
1055  static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
1056 @@ -129,8 +136,8 @@ static dbus_bool_t expire_incomplete_timeout (void *data);
1057  
1058  #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
1059  
1060 -static DBusLoop*
1061 -connection_get_loop (DBusConnection *connection)
1062 +DBusLoop*
1063 +bus_connection_get_loop (DBusConnection *connection)
1064  {
1065    BusConnectionData *d;
1066  
1067 @@ -354,7 +361,7 @@ add_connection_watch (DBusWatch      *watch,
1068  {
1069    DBusConnection *connection = data;
1070  
1071 -  return _dbus_loop_add_watch (connection_get_loop (connection), watch);
1072 +  return _dbus_loop_add_watch (bus_connection_get_loop (connection), watch);
1073  }
1074  
1075  static void
1076 @@ -363,7 +370,7 @@ remove_connection_watch (DBusWatch      *watch,
1077  {
1078    DBusConnection *connection = data;
1079    
1080 -  _dbus_loop_remove_watch (connection_get_loop (connection), watch);
1081 +  _dbus_loop_remove_watch (bus_connection_get_loop (connection), watch);
1082  }
1083  
1084  static void
1085 @@ -372,7 +379,7 @@ toggle_connection_watch (DBusWatch      *watch,
1086  {
1087    DBusConnection *connection = data;
1088  
1089 -  _dbus_loop_toggle_watch (connection_get_loop (connection), watch);
1090 +  _dbus_loop_toggle_watch (bus_connection_get_loop (connection), watch);
1091  }
1092  
1093  static dbus_bool_t
1094 @@ -381,7 +388,7 @@ add_connection_timeout (DBusTimeout    *timeout,
1095  {
1096    DBusConnection *connection = data;
1097    
1098 -  return _dbus_loop_add_timeout (connection_get_loop (connection), timeout);
1099 +  return _dbus_loop_add_timeout (bus_connection_get_loop (connection), timeout);
1100  }
1101  
1102  static void
1103 @@ -390,7 +397,7 @@ remove_connection_timeout (DBusTimeout    *timeout,
1104  {
1105    DBusConnection *connection = data;
1106    
1107 -  _dbus_loop_remove_timeout (connection_get_loop (connection), timeout);
1108 +  _dbus_loop_remove_timeout (bus_connection_get_loop (connection), timeout);
1109  }
1110  
1111  static void
1112 @@ -448,6 +455,10 @@ free_connection_data (void *data)
1113    
1114    dbus_free (d->name);
1115    
1116 +#ifdef DBUS_ENABLE_CYNARA
1117 +  free (d->cynara_session_id);
1118 +#endif
1119 +
1120    dbus_free (d);
1121  }
1122  
1123 @@ -1078,6 +1089,22 @@ bus_connection_get_policy (DBusConnection *connection)
1124    return d->policy;
1125  }
1126  
1127 +#ifdef DBUS_ENABLE_CYNARA
1128 +const char *bus_connection_get_cynara_session_id (DBusConnection *connection)
1129 +{
1130 +  BusConnectionData *d = BUS_CONNECTION_DATA (connection);
1131 +  _dbus_assert (d != NULL);
1132 +
1133 +  if (d->cynara_session_id == NULL)
1134 +    {
1135 +      unsigned long pid;
1136 +      if (dbus_connection_get_unix_process_id(connection, &pid))
1137 +        d->cynara_session_id = cynara_session_from_pid(pid);
1138 +    }
1139 +  return d->cynara_session_id;
1140 +}
1141 +#endif
1142 +
1143  static dbus_bool_t
1144  foreach_active (BusConnections               *connections,
1145                  BusConnectionForeachFunction  function,
1146 @@ -2333,6 +2360,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
1147                                    DBusMessage    *message)
1148  {
1149    DBusError error = DBUS_ERROR_INIT;
1150 +  BusResult res;
1151  
1152    /* We have to set the sender to the driver, and have
1153     * to check security policy since it was not done in
1154 @@ -2370,10 +2398,11 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
1155     * if we're actively capturing messages, it's nice to log that we
1156     * tried to send it and did not allow ourselves to do so.
1157     */
1158 -  if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
1159 -                                          transaction,
1160 -                                          NULL, connection, connection,
1161 -                                          message, NULL, &error))
1162 +  res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
1163 +                                           transaction,
1164 +                                           NULL, connection, connection, message, NULL,
1165 +                                           &error, NULL);
1166 +  if (res == BUS_RESULT_FALSE)
1167      {
1168        if (!bus_transaction_capture_error_reply (transaction, connection,
1169                                                  &error, message))
1170 @@ -2388,6 +2417,12 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
1171        dbus_error_free (&error);
1172        return TRUE;
1173      }
1174 +  else if (res == BUS_RESULT_LATER)
1175 +    {
1176 +      _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
1177 +      dbus_error_free (&error);
1178 +      return TRUE;
1179 +    }
1180  
1181    return bus_transaction_send (transaction, connection, message);
1182  }
1183 diff --git a/bus/connection.h b/bus/connection.h
1184 index 9e253ae..71078ea 100644
1185 --- a/bus/connection.h
1186 +++ b/bus/connection.h
1187 @@ -31,6 +31,7 @@
1188  typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection, 
1189                                                        void           *data);
1190  
1191 +DBusLoop*       bus_connection_get_loop           (DBusConnection *connection);
1192  
1193  BusConnections* bus_connections_new               (BusContext                   *context);
1194  BusConnections* bus_connections_ref               (BusConnections               *connections);
1195 @@ -124,6 +125,9 @@ dbus_bool_t bus_connection_be_monitor (DBusConnection  *connection,
1196                                         BusTransaction  *transaction,
1197                                         DBusList       **rules,
1198                                         DBusError       *error);
1199 +#ifdef DBUS_ENABLE_CYNARA
1200 +const char *bus_connection_get_cynara_session_id (DBusConnection *connection);
1201 +#endif
1202  
1203  /* transaction API so we can send or not send a block of messages as a whole */
1204  
1205 diff --git a/bus/cynara.c b/bus/cynara.c
1206 new file mode 100644
1207 index 0000000..57a4c45
1208 --- /dev/null
1209 +++ b/bus/cynara.c
1210 @@ -0,0 +1,374 @@
1211 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
1212 +/* cynara.c  Cynara runtime privilege checking
1213 + *
1214 + * Copyright (c) 2014 Samsung Electronics, Ltd.
1215 + *
1216 + * Licensed under the Academic Free License version 2.1
1217 + *
1218 + * This program is free software; you can redistribute it and/or modify
1219 + * it under the terms of the GNU General Public License as published by
1220 + * the Free Software Foundation; either version 2 of the License, or
1221 + * (at your option) any later version.
1222 + *
1223 + * This program is distributed in the hope that it will be useful,
1224 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1225 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1226 + * GNU General Public License for more details.
1227 + *
1228 + * You should have received a copy of the GNU General Public License
1229 + * along with this program; if not, write to the Free Software
1230 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
1231 + *
1232 + */
1233 +
1234 +#include <config.h>
1235 +#include "cynara.h"
1236 +#include "check.h"
1237 +#include "utils.h"
1238 +
1239 +#include <stdio.h>
1240 +
1241 +#include <dbus/dbus.h>
1242 +#include <dbus/dbus-watch.h>
1243 +#include <dbus/dbus-connection-internal.h>
1244 +#include <bus/connection.h>
1245 +#ifdef DBUS_ENABLE_CYNARA
1246 +#include <cynara-client-async.h>
1247 +#endif
1248 +
1249 +
1250 +#ifdef DBUS_ENABLE_CYNARA
1251 +typedef struct BusCynara
1252 +{
1253 +  int refcount;
1254 +
1255 +  BusContext   *context;
1256 +  BusCheck     *check;
1257 +  cynara_async *cynara;
1258 +  DBusWatch    *cynara_watch;
1259 +} BusCynara;
1260 +
1261 +#define USE_CYNARA_CACHE 1
1262 +#ifdef USE_CYNARA_CACHE
1263 +#define CYNARA_CACHE_SIZE 1000
1264 +#endif
1265 +
1266 +static dbus_bool_t bus_cynara_watch_callback(DBusWatch *watch,
1267 +                                             unsigned int flags,
1268 +                                             void *data);
1269 +
1270 +static void status_callback(int old_fd,
1271 +                            int new_fd,
1272 +                            cynara_async_status status,
1273 +                            void *user_status_data);
1274 +static void bus_cynara_check_response_callback (cynara_check_id check_id,
1275 +                                                cynara_async_call_cause cause,
1276 +                                                int response,
1277 +                                                void *user_response_data);
1278 +#endif
1279 +
1280 +
1281 +BusCynara *
1282 +bus_cynara_new(BusCheck *check, DBusError *error)
1283 +{
1284 +#ifdef DBUS_ENABLE_CYNARA
1285 +  BusContext *context;
1286 +  BusCynara *cynara;
1287 +  cynara_async_configuration *conf = NULL;
1288 +  int ret;
1289 +
1290 +  cynara = dbus_new(BusCynara, 1);
1291 +  if (cynara == NULL)
1292 +    {
1293 +      BUS_SET_OOM(error);
1294 +      return NULL;
1295 +    }
1296 +
1297 +  context = bus_check_get_context(check);
1298 +
1299 +  cynara->refcount = 1;
1300 +  cynara->check = check;
1301 +  cynara->context = context;
1302 +  cynara->cynara_watch = NULL;
1303 +
1304 +  ret = cynara_async_configuration_create(&conf);
1305 +  if (ret != CYNARA_API_SUCCESS)
1306 +    {
1307 +      dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to create Cynara configuration");
1308 +      goto out;
1309 +    }
1310 +
1311 +#ifdef CYNARA_CACHE_SIZE
1312 +  ret = cynara_async_configuration_set_cache_size(conf, CYNARA_CACHE_SIZE);
1313 +  if (ret != CYNARA_API_SUCCESS)
1314 +    {
1315 +      dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to Cynara cache size");
1316 +      goto out;
1317 +    }
1318 +#endif
1319 +
1320 +  ret = cynara_async_initialize(&cynara->cynara, conf, &status_callback, cynara);
1321 +  if (ret != CYNARA_API_SUCCESS)
1322 +    {
1323 +      dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to initialize Cynara client");
1324 +      goto out;
1325 +    }
1326 +
1327 +out:
1328 +  cynara_async_configuration_destroy(conf);
1329 +  if (ret != CYNARA_API_SUCCESS)
1330 +    {
1331 +      dbus_free(cynara);
1332 +      return NULL;
1333 +    }
1334 +
1335 +  return cynara;
1336 +#else
1337 +  return NULL;
1338 +#endif
1339 +}
1340 +
1341 +BusCynara *
1342 +bus_cynara_ref (BusCynara *cynara)
1343 +{
1344 +#ifdef DBUS_ENABLE_CYNARA
1345 +  _dbus_assert (cynara->refcount > 0);
1346 +  cynara->refcount += 1;
1347 +
1348 +  return cynara;
1349 +#else
1350 +  return NULL;
1351 +#endif
1352 +}
1353 +
1354 +void
1355 +bus_cynara_unref (BusCynara *cynara)
1356 +{
1357 +#ifdef DBUS_ENABLE_CYNARA
1358 +  _dbus_assert (cynara->refcount > 0);
1359 +
1360 +  cynara->refcount -= 1;
1361 +
1362 +  if (cynara->refcount == 0)
1363 +    {
1364 +      cynara_async_finish(cynara->cynara);
1365 +      dbus_free(cynara);
1366 +    }
1367 +#endif
1368 +}
1369 +
1370 +BusResult
1371 +bus_cynara_check_privilege (BusCynara *cynara,
1372 +                            DBusMessage *message,
1373 +                            DBusConnection *sender,
1374 +                            DBusConnection *addressed_recipient,
1375 +                            DBusConnection *proposed_recipient,
1376 +                            const char *privilege,
1377 +                            BusDeferredMessageStatus check_type,
1378 +                            BusDeferredMessage **deferred_message_param)
1379 +{
1380 +#ifdef DBUS_ENABLE_CYNARA
1381 +  int result;
1382 +  unsigned long uid;
1383 +  char *label;
1384 +  const char *session_id;
1385 +  char user[32];
1386 +  cynara_check_id check_id;
1387 +  DBusConnection *connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
1388 +  BusDeferredMessage *deferred_message;
1389 +  BusResult ret;
1390 +
1391 +  _dbus_assert(connection != NULL);
1392 +
1393 +  if (dbus_connection_get_unix_user(connection, &uid) == FALSE)
1394 +      return BUS_RESULT_FALSE;
1395 +
1396 +  if (_dbus_connection_get_linux_security_label(connection, &label) == FALSE || label == NULL)
1397 +    {
1398 +      _dbus_warn("Failed to obtain security label for connection\n");
1399 +      return BUS_RESULT_FALSE;
1400 +    }
1401 +
1402 +  session_id = bus_connection_get_cynara_session_id (connection);
1403 +  if (session_id == NULL)
1404 +    {
1405 +      ret = BUS_RESULT_FALSE;
1406 +      goto out;
1407 +    }
1408 +
1409 +  snprintf(user, sizeof(user), "%lu", uid);
1410 +
1411 +#if USE_CYNARA_CACHE
1412 +  result = cynara_async_check_cache(cynara->cynara, label, session_id, user, privilege);
1413 +#else
1414 +  result = CYNARA_API_CACHE_MISS;
1415 +#endif
1416 +
1417 +  switch (result)
1418 +  {
1419 +  case CYNARA_API_ACCESS_ALLOWED:
1420 +    _dbus_verbose("Cynara: got ALLOWED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
1421 +               label, session_id, user, privilege);
1422 +    ret = BUS_RESULT_TRUE;
1423 +    break;
1424 +
1425 +  case CYNARA_API_ACCESS_DENIED:
1426 +    _dbus_verbose("Cynara: got DENIED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
1427 +               label, session_id, user, privilege);
1428 +    ret = BUS_RESULT_FALSE;
1429 +    break;
1430 +
1431 +  case CYNARA_API_CACHE_MISS:
1432 +     deferred_message = bus_deferred_message_new(message, sender, addressed_recipient,
1433 +         proposed_recipient, BUS_RESULT_LATER);
1434 +     if (deferred_message == NULL)
1435 +       {
1436 +         _dbus_verbose("Failed to allocate memory for deferred message\n");
1437 +         ret = BUS_RESULT_FALSE;
1438 +         goto out;
1439 +       }
1440 +
1441 +    /* callback is supposed to unref deferred_message*/
1442 +    result = cynara_async_create_request(cynara->cynara, label, session_id, user, privilege, &check_id,
1443 +        &bus_cynara_check_response_callback, deferred_message);
1444 +    if (result == CYNARA_API_SUCCESS)
1445 +      {
1446 +        _dbus_verbose("Created Cynara request: client=%s session_id=%s user=%s privilege=%s check_id=%u "
1447 +            "deferred_message=%p\n", label, session_id, user, privilege, (unsigned int)check_id, deferred_message);
1448 +        if (deferred_message_param != NULL)
1449 +          *deferred_message_param = deferred_message;
1450 +        ret = BUS_RESULT_LATER;
1451 +      }
1452 +    else
1453 +      {
1454 +        _dbus_verbose("Error on cynara request create: %i\n", result);
1455 +        bus_deferred_message_unref(deferred_message);
1456 +        ret = BUS_RESULT_FALSE;
1457 +      }
1458 +    break;
1459 +  default:
1460 +    _dbus_verbose("Error when accessing Cynara cache: %i\n", result);
1461 +    ret = BUS_RESULT_FALSE;
1462 +  }
1463 +out:
1464 +  dbus_free(label);
1465 +  return ret;
1466 +
1467 +#else
1468 +  return BUS_RESULT_FALSE;
1469 +#endif
1470 +}
1471 +
1472 +
1473 +
1474 +#ifdef DBUS_ENABLE_CYNARA
1475 +static void
1476 +status_callback(int old_fd, int new_fd, cynara_async_status status,
1477 +                void *user_status_data)
1478 +{
1479 +  BusCynara *cynara = (BusCynara *)user_status_data;
1480 +  DBusLoop *loop = bus_context_get_loop(cynara->context);
1481 +
1482 +  if (cynara->cynara_watch != NULL)
1483 +    {
1484 +      _dbus_loop_remove_watch(loop, cynara->cynara_watch);
1485 +      _dbus_watch_invalidate(cynara->cynara_watch);
1486 +      _dbus_watch_unref(cynara->cynara_watch);
1487 +      cynara->cynara_watch = NULL;
1488 +    }
1489 +
1490 +  if (new_fd != -1)
1491 +    {
1492 +      unsigned int flags;
1493 +      DBusWatch *watch;
1494 +
1495 +      switch (status)
1496 +      {
1497 +      case CYNARA_STATUS_FOR_READ:
1498 +        flags = DBUS_WATCH_READABLE;
1499 +        break;
1500 +      case CYNARA_STATUS_FOR_RW:
1501 +        flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
1502 +        break;
1503 +      default:
1504 +        /* Cynara passed unknown status - warn and add RW watch */
1505 +        _dbus_verbose("Cynara passed unknown status value: 0x%08X\n", (unsigned int)status);
1506 +        flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
1507 +        break;
1508 +      }
1509 +
1510 +      watch = _dbus_watch_new(new_fd, flags, TRUE, &bus_cynara_watch_callback, cynara, NULL);
1511 +      if (watch != NULL)
1512 +        {
1513 +          if (_dbus_loop_add_watch(loop, watch) == TRUE)
1514 +            {
1515 +              cynara->cynara_watch = watch;
1516 +              return;
1517 +            }
1518 +
1519 +          _dbus_watch_invalidate(watch);
1520 +          _dbus_watch_unref(watch);
1521 +        }
1522 +
1523 +      /* It seems like not much can be done at this point. Cynara events won't be processed
1524 +       * until next Cynara function call triggering status callback */
1525 +      _dbus_verbose("Failed to add dbus watch\n");
1526 +    }
1527 +}
1528 +
1529 +static dbus_bool_t
1530 +bus_cynara_watch_callback(DBusWatch    *watch,
1531 +                          unsigned int  flags,
1532 +                          void         *data)
1533 +{
1534 +  BusCynara *cynara = (BusCynara *)data;
1535 +  int result = cynara_async_process(cynara->cynara);
1536 +  if (result != CYNARA_API_SUCCESS)
1537 +      _dbus_verbose("cynara_async_process returned %d\n", result);
1538 +
1539 +  return result != CYNARA_API_OUT_OF_MEMORY ? TRUE : FALSE;
1540 +}
1541 +
1542 +static inline const char *
1543 +call_cause_to_string(cynara_async_call_cause cause)
1544 +{
1545 +  switch (cause)
1546 +  {
1547 +  case CYNARA_CALL_CAUSE_ANSWER:
1548 +    return "ANSWER";
1549 +  case CYNARA_CALL_CAUSE_CANCEL:
1550 +    return "CANCEL";
1551 +  case CYNARA_CALL_CAUSE_FINISH:
1552 +    return "FINSIH";
1553 +  case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE:
1554 +    return "SERVICE NOT AVAILABLE";
1555 +  default:
1556 +    return "INVALID";
1557 +  }
1558 +}
1559 +
1560 +static void
1561 +bus_cynara_check_response_callback (cynara_check_id check_id,
1562 +                                    cynara_async_call_cause cause,
1563 +                                    int response,
1564 +                                    void *user_response_data)
1565 +{
1566 +  BusDeferredMessage *deferred_message = user_response_data;
1567 +  BusResult result;
1568 +
1569 +  _dbus_verbose("Cynara callback: check_id=%u, cause=%s response=%i response_data=%p\n",
1570 +      (unsigned int)check_id, call_cause_to_string(cause), response, user_response_data);
1571 +
1572 +  if (deferred_message == NULL)
1573 +    return;
1574 +
1575 +  if (cause == CYNARA_CALL_CAUSE_ANSWER && response == CYNARA_API_ACCESS_ALLOWED)
1576 +    result = BUS_RESULT_TRUE;
1577 +  else
1578 +    result = BUS_RESULT_FALSE;
1579 +
1580 +  bus_deferred_message_response_received(deferred_message, result);
1581 +  bus_deferred_message_unref(deferred_message);
1582 +}
1583 +
1584 +#endif /* DBUS_ENABLE_CYNARA */
1585 diff --git a/bus/cynara.h b/bus/cynara.h
1586 new file mode 100644
1587 index 0000000..c4728bb
1588 --- /dev/null
1589 +++ b/bus/cynara.h
1590 @@ -0,0 +1,37 @@
1591 +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
1592 +/* cynara.h  Cynara runtime privilege checking
1593 + *
1594 + * Copyright (c) 2014 Samsung Electronics, Ltd.
1595 + *
1596 + * Licensed under the Academic Free License version 2.1
1597 + *
1598 + * This program is free software; you can redistribute it and/or modify
1599 + * it under the terms of the GNU General Public License as published by
1600 + * the Free Software Foundation; either version 2 of the License, or
1601 + * (at your option) any later version.
1602 + *
1603 + * This program is distributed in the hope that it will be useful,
1604 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1605 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1606 + * GNU General Public License for more details.
1607 + *
1608 + * You should have received a copy of the GNU General Public License
1609 + * along with this program; if not, write to the Free Software
1610 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
1611 + *
1612 + */
1613 +
1614 +#include "bus.h"
1615 +#include "check.h"
1616 +
1617 +BusCynara *bus_cynara_new             (BusCheck *check, DBusError *error);
1618 +BusCynara *bus_cynara_ref             (BusCynara *cynara);
1619 +void       bus_cynara_unref           (BusCynara *cynara);
1620 +BusResult  bus_cynara_check_privilege (BusCynara *cynara,
1621 +                                       DBusMessage *message,
1622 +                                       DBusConnection *sender,
1623 +                                       DBusConnection *addressed_recipient,
1624 +                                       DBusConnection *proposed_recipient,
1625 +                                       const char *privilege,
1626 +                                       BusDeferredMessageStatus check_type,
1627 +                                       BusDeferredMessage **deferred_message);
1628 diff --git a/bus/dispatch.c b/bus/dispatch.c
1629 index 19228be..d3867f7 100644
1630 --- a/bus/dispatch.c
1631 +++ b/bus/dispatch.c
1632 @@ -25,6 +25,7 @@
1633  
1634  #include <config.h>
1635  #include "dispatch.h"
1636 +#include "check.h"
1637  #include "connection.h"
1638  #include "driver.h"
1639  #include "services.h"
1640 @@ -64,14 +65,18 @@ send_one_message (DBusConnection *connection,
1641                    DBusError      *error)
1642  {
1643    DBusError stack_error = DBUS_ERROR_INIT;
1644 +  BusDeferredMessage *deferred_message;
1645 +  BusResult result;
1646  
1647 -  if (!bus_context_check_security_policy (context, transaction,
1648 +  result = bus_context_check_security_policy (context, transaction,
1649                                            sender,
1650                                            addressed_recipient,
1651                                            connection,
1652                                            message,
1653                                            NULL,
1654 -                                          &stack_error))
1655 +                                          &stack_error,
1656 +                                          &deferred_message);
1657 +  if (result != BUS_RESULT_TRUE)
1658      {
1659        if (!bus_transaction_capture_error_reply (transaction, sender,
1660                                                  &stack_error, message))
1661 @@ -130,6 +135,8 @@ bus_dispatch_matches (BusTransaction *transaction,
1662    BusMatchmaker *matchmaker;
1663    DBusList *link;
1664    BusContext *context;
1665 +  BusDeferredMessage *deferred_message;
1666 +  BusResult res;
1667  
1668    _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1669  
1670 @@ -145,11 +152,20 @@ bus_dispatch_matches (BusTransaction *transaction,
1671    /* First, send the message to the addressed_recipient, if there is one. */
1672    if (addressed_recipient != NULL)
1673      {
1674 -      if (!bus_context_check_security_policy (context, transaction,
1675 -                                              sender, addressed_recipient,
1676 -                                              addressed_recipient,
1677 -                                              message, NULL, error))
1678 +      res = bus_context_check_security_policy (context, transaction,
1679 +                                               sender, addressed_recipient,
1680 +                                               addressed_recipient,
1681 +                                               message, NULL, error,
1682 +                                               &deferred_message);
1683 +      if (res == BUS_RESULT_FALSE)
1684          return FALSE;
1685 +      else if (res == BUS_RESULT_LATER)
1686 +        {
1687 +          dbus_set_error (error,
1688 +                          DBUS_ERROR_ACCESS_DENIED,
1689 +                          "Rejecting message because time is needed to check security policy");
1690 +          return FALSE;
1691 +        }
1692  
1693        if (dbus_message_contains_unix_fds (message) &&
1694            !dbus_connection_can_send_type (addressed_recipient,
1695 @@ -374,19 +390,31 @@ bus_dispatch (DBusConnection *connection,
1696    if (service_name &&
1697        strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
1698      {
1699 +      BusDeferredMessage *deferred_message;
1700 +      BusResult res;
1701 +
1702        if (!bus_transaction_capture (transaction, connection, NULL, message))
1703          {
1704            BUS_SET_OOM (&error);
1705            goto out;
1706          }
1707  
1708 -      if (!bus_context_check_security_policy (context, transaction,
1709 -                                              connection, NULL, NULL, message,
1710 -                                              NULL, &error))
1711 +      res = bus_context_check_security_policy (context, transaction,
1712 +                                               connection, NULL, NULL, message, NULL,
1713 +                                               &error, &deferred_message);
1714 +      if (res == BUS_RESULT_FALSE)
1715          {
1716            _dbus_verbose ("Security policy rejected message\n");
1717            goto out;
1718          }
1719 +      else if (res == BUS_RESULT_LATER)
1720 +        {
1721 +          dbus_set_error (&error,
1722 +                          DBUS_ERROR_ACCESS_DENIED,
1723 +                          "Rejecting message because time is needed to check security policy");
1724 +          _dbus_verbose ("Security policy needs time to check policy. Dropping message\n");
1725 +          goto out;
1726 +        }
1727  
1728        _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS);
1729        if (!bus_driver_handle_message (connection, transaction, message, &error))
1730 diff --git a/bus/driver.h b/bus/driver.h
1731 index ac1289d..a7297ad 100644
1732 --- a/bus/driver.h
1733 +++ b/bus/driver.h
1734 @@ -66,5 +66,7 @@ dbus_bool_t bus_driver_send_ack_reply     (DBusConnection  *connection,
1735                                             BusTransaction  *transaction,
1736                                             DBusMessage     *message,
1737                                             DBusError       *error);
1738 +dbus_bool_t bus_driver_check_message_is_for_us (DBusMessage *message,
1739 +                                                DBusError   *error);
1740  
1741  #endif /* BUS_DRIVER_H */
1742 diff --git a/bus/policy.c b/bus/policy.c
1743 index a37be80..7de92c6 100644
1744 --- a/bus/policy.c
1745 +++ b/bus/policy.c
1746 @@ -22,6 +22,7 @@
1747   */
1748  
1749  #include <config.h>
1750 +#include "check.h"
1751  #include "policy.h"
1752  #include "services.h"
1753  #include "test.h"
1754 @@ -33,7 +34,7 @@
1755  
1756  BusPolicyRule*
1757  bus_policy_rule_new (BusPolicyRuleType type,
1758 -                     dbus_bool_t       allow)
1759 +                     BusPolicyRuleAccess access)
1760  {
1761    BusPolicyRule *rule;
1762  
1763 @@ -43,7 +44,7 @@ bus_policy_rule_new (BusPolicyRuleType type,
1764  
1765    rule->type = type;
1766    rule->refcount = 1;
1767 -  rule->allow = allow;
1768 +  rule->access = access;
1769  
1770    switch (rule->type)
1771      {
1772 @@ -55,18 +56,19 @@ bus_policy_rule_new (BusPolicyRuleType type,
1773        break;
1774      case BUS_POLICY_RULE_SEND:
1775        rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
1776 -
1777        /* allow rules default to TRUE (only requested replies allowed)
1778 +       * check rules default to TRUE (only requested replies are checked)
1779         * deny rules default to FALSE (only unrequested replies denied)
1780         */
1781 -      rule->d.send.requested_reply = rule->allow;
1782 +      rule->d.send.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
1783        break;
1784      case BUS_POLICY_RULE_RECEIVE:
1785        rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
1786        /* allow rules default to TRUE (only requested replies allowed)
1787 +       * check rules default to TRUE (only requested replies are checked)
1788         * deny rules default to FALSE (only unrequested replies denied)
1789         */
1790 -      rule->d.receive.requested_reply = rule->allow;
1791 +      rule->d.receive.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
1792        break;
1793      case BUS_POLICY_RULE_OWN:
1794        break;
1795 @@ -122,7 +124,8 @@ bus_policy_rule_unref (BusPolicyRule *rule)
1796          default:
1797            _dbus_assert_not_reached ("invalid rule");
1798          }
1799 -      
1800 +
1801 +      dbus_free (rule->privilege);
1802        dbus_free (rule);
1803      }
1804  }
1805 @@ -435,7 +438,10 @@ list_allows_user (dbus_bool_t           def,
1806        else
1807          continue;
1808  
1809 -      allowed = rule->allow;
1810 +      /* We don't intend to support <check user="..." /> and <check group="..." />
1811 +         rules. They are treated like deny.
1812 +      */
1813 +      allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
1814      }
1815    
1816    return allowed;
1817 @@ -873,18 +879,23 @@ bus_client_policy_append_rule (BusClientPolicy *policy,
1818    return TRUE;
1819  }
1820  
1821 -dbus_bool_t
1822 -bus_client_policy_check_can_send (BusClientPolicy *policy,
1823 -                                  BusRegistry     *registry,
1824 -                                  dbus_bool_t      requested_reply,
1825 -                                  DBusConnection  *receiver,
1826 -                                  DBusMessage     *message,
1827 -                                  dbus_int32_t    *toggles,
1828 -                                  dbus_bool_t     *log)
1829 +BusResult
1830 +bus_client_policy_check_can_send (DBusConnection      *sender,
1831 +                                  BusClientPolicy     *policy,
1832 +                                  BusRegistry         *registry,
1833 +                                  dbus_bool_t          requested_reply,
1834 +                                  DBusConnection      *addressed_recipient,
1835 +                                  DBusConnection      *receiver,
1836 +                                  DBusMessage         *message,
1837 +                                  dbus_int32_t        *toggles,
1838 +                                  dbus_bool_t         *log,
1839 +                                  const char         **privilege_param,
1840 +                                  BusDeferredMessage **deferred_message)
1841  {
1842    DBusList *link;
1843 -  dbus_bool_t allowed;
1844 -  
1845 +  BusResult result;
1846 +  const char *privilege;
1847 +
1848    /* policy->rules is in the order the rules appeared
1849     * in the config file, i.e. last rule that applies wins
1850     */
1851 @@ -892,7 +903,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1852    _dbus_verbose ("  (policy) checking send rules\n");
1853    *toggles = 0;
1854    
1855 -  allowed = FALSE;
1856 +  result = BUS_RESULT_FALSE;
1857    link = _dbus_list_get_first_link (&policy->rules);
1858    while (link != NULL)
1859      {
1860 @@ -923,13 +934,14 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1861        /* If it's a reply, the requested_reply flag kicks in */
1862        if (dbus_message_get_reply_serial (message) != 0)
1863          {
1864 -          /* for allow, requested_reply=true means the rule applies
1865 -           * only when reply was requested. requested_reply=false means
1866 -           * always allow.
1867 +          /* for allow or check requested_reply=true means the rule applies
1868 +           * only when reply was requested. requested_reply=false means the
1869 +           * rule always applies
1870             */
1871 -          if (!requested_reply && rule->allow && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
1872 +          if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
1873              {
1874 -              _dbus_verbose ("  (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
1875 +              _dbus_verbose ("  (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
1876 +                  rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
1877                continue;
1878              }
1879  
1880 @@ -937,7 +949,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1881             * when the reply was not requested. requested_reply=true means the
1882             * rule always applies.
1883             */
1884 -          if (requested_reply && !rule->allow && !rule->d.send.requested_reply)
1885 +          if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.send.requested_reply)
1886              {
1887                _dbus_verbose ("  (policy) skipping deny rule since it only applies to unrequested replies\n");
1888                continue;
1889 @@ -960,13 +972,15 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1890            /* The interface is optional in messages. For allow rules, if the message
1891             * has no interface we want to skip the rule (and thus not allow);
1892             * for deny rules, if the message has no interface we want to use the
1893 -           * rule (and thus deny).
1894 +           * rule (and thus deny). Check rules are meant to be used like allow
1895 +           * rules (they can grant access, but not remove it), so we treat it like
1896 +           * allow here.
1897             */
1898            dbus_bool_t no_interface;
1899  
1900            no_interface = dbus_message_get_interface (message) == NULL;
1901            
1902 -          if ((no_interface && rule->allow) ||
1903 +          if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
1904                (!no_interface && 
1905                 strcmp (dbus_message_get_interface (message),
1906                         rule->d.send.interface) != 0))
1907 @@ -1079,33 +1093,64 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
1908          }
1909  
1910        /* Use this rule */
1911 -      allowed = rule->allow;
1912 +      switch (rule->access)
1913 +        {
1914 +        case BUS_POLICY_RULE_ACCESS_ALLOW:
1915 +          result = BUS_RESULT_TRUE;
1916 +          break;
1917 +        case BUS_POLICY_RULE_ACCESS_DENY:
1918 +        default:
1919 +          result = BUS_RESULT_FALSE;
1920 +          break;
1921 +        case BUS_POLICY_RULE_ACCESS_CHECK:
1922 +          result = BUS_RESULT_LATER;
1923 +          privilege = rule->privilege;
1924 +          break;
1925 +        }
1926 +
1927        *log = rule->d.send.log;
1928        (*toggles)++;
1929  
1930 -      _dbus_verbose ("  (policy) used rule, allow now = %d\n",
1931 -                     allowed);
1932 +      _dbus_verbose ("  (policy) used rule, result now = %d\n",
1933 +                     (int)(intptr_t)result);
1934      }
1935  
1936 -  return allowed;
1937 +  if (result == BUS_RESULT_LATER)
1938 +    {
1939 +      BusContext *context = bus_connection_get_context(sender);
1940 +      BusCheck *check = bus_context_get_check(context);
1941 +
1942 +      result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
1943 +          privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
1944 +    }
1945 +  else
1946 +    privilege = NULL;
1947 +
1948 +  if (privilege_param != NULL)
1949 +    *privilege_param = privilege;
1950 +
1951 +  return result;
1952  }
1953  
1954  /* See docs on what the args mean on bus_context_check_security_policy()
1955   * comment
1956   */
1957 -dbus_bool_t
1958 -bus_client_policy_check_can_receive (BusClientPolicy *policy,
1959 -                                     BusRegistry     *registry,
1960 -                                     dbus_bool_t      requested_reply,
1961 -                                     DBusConnection  *sender,
1962 -                                     DBusConnection  *addressed_recipient,
1963 -                                     DBusConnection  *proposed_recipient,
1964 -                                     DBusMessage     *message,
1965 -                                     dbus_int32_t    *toggles)
1966 +BusResult
1967 +bus_client_policy_check_can_receive (BusClientPolicy     *policy,
1968 +                                     BusRegistry         *registry,
1969 +                                     dbus_bool_t          requested_reply,
1970 +                                     DBusConnection      *sender,
1971 +                                     DBusConnection      *addressed_recipient,
1972 +                                     DBusConnection      *proposed_recipient,
1973 +                                     DBusMessage         *message,
1974 +                                     dbus_int32_t        *toggles,
1975 +                                     const char         **privilege_param,
1976 +                                     BusDeferredMessage **deferred_message)
1977  {
1978    DBusList *link;
1979 -  dbus_bool_t allowed;
1980    dbus_bool_t eavesdropping;
1981 +  BusResult result;
1982 +  const char *privilege;
1983  
1984    eavesdropping =
1985      addressed_recipient != proposed_recipient &&
1986 @@ -1118,7 +1163,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1987    _dbus_verbose ("  (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
1988    *toggles = 0;
1989    
1990 -  allowed = FALSE;
1991 +  result = BUS_RESULT_FALSE;
1992    link = _dbus_list_get_first_link (&policy->rules);
1993    while (link != NULL)
1994      {
1995 @@ -1141,19 +1186,21 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
1996              }
1997          }
1998  
1999 -      /* for allow, eavesdrop=false means the rule doesn't apply when
2000 -       * eavesdropping. eavesdrop=true means always allow.
2001 +
2002 +      /* for allow or check, eavesdrop=false means the rule doesn't apply when
2003 +       * eavesdropping. eavesdrop=true means the rule always applies
2004         */
2005 -      if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop)
2006 +      if (eavesdropping && rule->access != BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.eavesdrop)
2007          {
2008 -          _dbus_verbose ("  (policy) skipping allow rule since it doesn't apply to eavesdropping\n");
2009 +          _dbus_verbose ("  (policy) skipping %s rule since it doesn't apply to eavesdropping\n",
2010 +              rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
2011            continue;
2012          }
2013  
2014        /* for deny, eavesdrop=true means the rule applies only when
2015         * eavesdropping; eavesdrop=false means always deny.
2016         */
2017 -      if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop)
2018 +      if (!eavesdropping && rule->access == BUS_POLICY_RULE_ACCESS_DENY && rule->d.receive.eavesdrop)
2019          {
2020            _dbus_verbose ("  (policy) skipping deny rule since it only applies to eavesdropping\n");
2021            continue;
2022 @@ -1162,13 +1209,14 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
2023        /* If it's a reply, the requested_reply flag kicks in */
2024        if (dbus_message_get_reply_serial (message) != 0)
2025          {
2026 -          /* for allow, requested_reply=true means the rule applies
2027 -           * only when reply was requested. requested_reply=false means
2028 -           * always allow.
2029 +          /* for allow or check requested_reply=true means the rule applies
2030 +           * only when reply was requested. requested_reply=false means the
2031 +           * rule always applies
2032             */
2033 -          if (!requested_reply && rule->allow && rule->d.receive.requested_reply && !rule->d.receive.eavesdrop)
2034 +          if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
2035              {
2036 -              _dbus_verbose ("  (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
2037 +              _dbus_verbose ("  (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
2038 +                  rule->access == BUS_POLICY_RULE_ACCESS_DENY ? "allow" : "deny");
2039                continue;
2040              }
2041  
2042 @@ -1176,7 +1224,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
2043             * when the reply was not requested. requested_reply=true means the
2044             * rule always applies.
2045             */
2046 -          if (requested_reply && !rule->allow && !rule->d.receive.requested_reply)
2047 +          if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.requested_reply)
2048              {
2049                _dbus_verbose ("  (policy) skipping deny rule since it only applies to unrequested replies\n");
2050                continue;
2051 @@ -1199,13 +1247,13 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
2052            /* The interface is optional in messages. For allow rules, if the message
2053             * has no interface we want to skip the rule (and thus not allow);
2054             * for deny rules, if the message has no interface we want to use the
2055 -           * rule (and thus deny).
2056 +           * rule (and thus deny). Check rules are treated like allow rules.
2057             */
2058            dbus_bool_t no_interface;
2059  
2060            no_interface = dbus_message_get_interface (message) == NULL;
2061            
2062 -          if ((no_interface && rule->allow) ||
2063 +          if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
2064                (!no_interface &&
2065                 strcmp (dbus_message_get_interface (message),
2066                         rule->d.receive.interface) != 0))
2067 @@ -1295,14 +1343,43 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
2068          }
2069  
2070        /* Use this rule */
2071 -      allowed = rule->allow;
2072 +      switch (rule->access)
2073 +      {
2074 +        case BUS_POLICY_RULE_ACCESS_ALLOW:
2075 +          result = BUS_RESULT_TRUE;
2076 +          break;
2077 +        case BUS_POLICY_RULE_ACCESS_DENY:
2078 +        default:
2079 +          result = BUS_RESULT_FALSE;
2080 +          break;
2081 +        case BUS_POLICY_RULE_ACCESS_CHECK:
2082 +          result = BUS_RESULT_LATER;
2083 +          privilege = rule->privilege;
2084 +          break;
2085 +      }
2086 +
2087        (*toggles)++;
2088  
2089 -      _dbus_verbose ("  (policy) used rule, allow now = %d\n",
2090 -                     allowed);
2091 +      _dbus_verbose ("  (policy) used rule, result now = %d\n",
2092 +                     (int)(intptr_t)result);
2093      }
2094  
2095 -  return allowed;
2096 +
2097 +  if (result == BUS_RESULT_LATER)
2098 +    {
2099 +      BusContext *context = bus_connection_get_context(proposed_recipient);
2100 +      BusCheck *check = bus_context_get_check(context);
2101 +
2102 +      result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
2103 +                 privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
2104 +    }
2105 +  else
2106 +      privilege = NULL;
2107 +
2108 +  if (privilege_param != NULL)
2109 +     *privilege_param = privilege;
2110 +
2111 +  return result;
2112  }
2113  
2114  
2115 @@ -1354,7 +1431,7 @@ bus_rules_check_can_own (DBusList *rules,
2116          }
2117  
2118        /* Use this rule */
2119 -      allowed = rule->allow;
2120 +      allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
2121      }
2122  
2123    return allowed;
2124 diff --git a/bus/policy.h b/bus/policy.h
2125 index ec43ffa..f839d23 100644
2126 --- a/bus/policy.h
2127 +++ b/bus/policy.h
2128 @@ -46,6 +46,14 @@ typedef enum
2129    BUS_POLICY_TRISTATE_TRUE
2130  } BusPolicyTristate;
2131  
2132 +typedef enum
2133 +{
2134 +  BUS_POLICY_RULE_ACCESS_DENY,
2135 +  BUS_POLICY_RULE_ACCESS_ALLOW,
2136 +  /** runtime check resulting in allow or deny */
2137 +  BUS_POLICY_RULE_ACCESS_CHECK
2138 +} BusPolicyRuleAccess;
2139 +
2140  /** determines whether the rule affects a connection, or some global item */
2141  #define BUS_POLICY_RULE_IS_PER_CLIENT(rule) (!((rule)->type == BUS_POLICY_RULE_USER || \
2142                                                 (rule)->type == BUS_POLICY_RULE_GROUP))
2143 @@ -56,8 +64,9 @@ struct BusPolicyRule
2144    
2145    BusPolicyRuleType type;
2146  
2147 -  unsigned int allow : 1; /**< #TRUE if this allows, #FALSE if it denies */
2148 -  
2149 +  unsigned int access : 2; /**< BusPolicyRuleAccess */
2150 +  char *privilege; /**< for BUS_POLICY_RULE_ACCESS_CHECK */
2151 +
2152    union
2153    {
2154      struct
2155 @@ -118,7 +127,7 @@ struct BusPolicyRule
2156  };
2157  
2158  BusPolicyRule* bus_policy_rule_new   (BusPolicyRuleType type,
2159 -                                      dbus_bool_t       allow);
2160 +                                      BusPolicyRuleAccess access);
2161  BusPolicyRule* bus_policy_rule_ref   (BusPolicyRule    *rule);
2162  void           bus_policy_rule_unref (BusPolicyRule    *rule);
2163  
2164 @@ -152,21 +161,27 @@ dbus_bool_t      bus_policy_merge                 (BusPolicy        *policy,
2165  BusClientPolicy* bus_client_policy_new               (void);
2166  BusClientPolicy* bus_client_policy_ref               (BusClientPolicy  *policy);
2167  void             bus_client_policy_unref             (BusClientPolicy  *policy);
2168 -dbus_bool_t      bus_client_policy_check_can_send    (BusClientPolicy  *policy,
2169 +BusResult        bus_client_policy_check_can_send    (DBusConnection   *sender,
2170 +                                                      BusClientPolicy  *policy,
2171                                                        BusRegistry      *registry,
2172                                                        dbus_bool_t       requested_reply,
2173 +                                                      DBusConnection   *addressed_recipient,
2174                                                        DBusConnection   *receiver,
2175                                                        DBusMessage      *message,
2176                                                        dbus_int32_t     *toggles,
2177 -                                                      dbus_bool_t      *log);
2178 -dbus_bool_t      bus_client_policy_check_can_receive (BusClientPolicy  *policy,
2179 +                                                      dbus_bool_t      *log,
2180 +                                                      const char      **privilege_param,
2181 +                                                      BusDeferredMessage **deferred_message);
2182 +BusResult        bus_client_policy_check_can_receive (BusClientPolicy  *policy,
2183                                                        BusRegistry      *registry,
2184                                                        dbus_bool_t       requested_reply,
2185                                                        DBusConnection   *sender,
2186                                                        DBusConnection   *addressed_recipient,
2187                                                        DBusConnection   *proposed_recipient,
2188                                                        DBusMessage      *message,
2189 -                                                      dbus_int32_t     *toggles);
2190 +                                                      dbus_int32_t     *toggles,
2191 +                                                      const char      **privilege_param,
2192 +                                                      BusDeferredMessage **deferred_message);
2193  dbus_bool_t      bus_client_policy_check_can_own     (BusClientPolicy  *policy,
2194                                                        const DBusString *service_name);
2195  dbus_bool_t      bus_client_policy_append_rule       (BusClientPolicy  *policy,
2196 diff --git a/configure.ac b/configure.ac
2197 index d1e3a29..11b5ffd 100644
2198 --- a/configure.ac
2199 +++ b/configure.ac
2200 @@ -1742,6 +1742,17 @@ AC_ARG_ENABLE([user-session],
2201  AM_CONDITIONAL([DBUS_ENABLE_USER_SESSION],
2202    [test "x$enable_user_session" = xyes])
2203  
2204 +#enable cynara integration
2205 +AC_ARG_ENABLE([cynara], [AS_HELP_STRING([--enable-cynara], [enable Cynara integration])], [], [enable_cynara=no])
2206 +if test "x$enable_cynara" = xyes; then
2207 +  PKG_CHECK_MODULES([CYNARA], [cynara-client-async >= 0.6.0 cynara-session >= 0.6.0],
2208 +     [AC_DEFINE([DBUS_ENABLE_CYNARA], [1], [Define to enable Cynara privilege checks in dbus-daemon])],
2209 +     [AC_MSG_ERROR([libcynara-client-async and cynara-session are required to enable Cynara integration])])
2210 +fi
2211 +
2212 +AC_SUBST([CYNARA_CFLAGS])
2213 +AC_SUBST([CYNARA_LIBS])
2214 +
2215  AC_CONFIG_FILES([
2216  Doxyfile
2217  dbus/Version
2218 @@ -1824,6 +1835,7 @@ echo "
2219          Building bus stats API:   ${enable_stats}
2220          Building SELinux support: ${have_selinux}
2221          Building AppArmor support: ${have_apparmor}
2222 +        Building Cynara support:  ${enable_cynara}
2223          Building inotify support: ${have_inotify}
2224          Building kqueue support:  ${have_kqueue}
2225          Building systemd support: ${have_systemd}
2226 diff --git a/test/Makefile.am b/test/Makefile.am
2227 index af1e13b..e6f50e1 100644
2228 --- a/test/Makefile.am
2229 +++ b/test/Makefile.am
2230 @@ -439,6 +439,7 @@ in_data = \
2231         data/valid-config-files/debug-allow-all.conf.in \
2232         data/valid-config-files/finite-timeout.conf.in \
2233         data/valid-config-files/forbidding.conf.in \
2234 +       data/valid-config-files/debug-check-some.conf.in \
2235         data/valid-config-files/incoming-limit.conf.in \
2236         data/valid-config-files/max-completed-connections.conf.in \
2237         data/valid-config-files/max-connections-per-user.conf.in \
2238 diff --git a/test/data/invalid-config-files/badcheck-1.conf b/test/data/invalid-config-files/badcheck-1.conf
2239 new file mode 100644
2240 index 0000000..fad9f50
2241 --- /dev/null
2242 +++ b/test/data/invalid-config-files/badcheck-1.conf
2243 @@ -0,0 +1,9 @@
2244 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2245 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2246 +<busconfig>
2247 +  <user>mybususer</user>
2248 +  <listen>unix:path=/foo/bar</listen>
2249 +  <policy context="default">
2250 +    <allow privilege="foo" send_destination="*"/> <!-- extra privilege="foo" -->
2251 +  </policy>
2252 +</busconfig>
2253 diff --git a/test/data/invalid-config-files/badcheck-2.conf b/test/data/invalid-config-files/badcheck-2.conf
2254 new file mode 100644
2255 index 0000000..63c7ef2
2256 --- /dev/null
2257 +++ b/test/data/invalid-config-files/badcheck-2.conf
2258 @@ -0,0 +1,9 @@
2259 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2260 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2261 +<busconfig>
2262 +  <user>mybususer</user>
2263 +  <listen>unix:path=/foo/bar</listen>
2264 +  <policy context="default">
2265 +    <check send_destination="*"/> <!-- missing privilege="foo" -->
2266 +  </policy>
2267 +</busconfig>
2268 diff --git a/test/data/valid-config-files/check-1.conf b/test/data/valid-config-files/check-1.conf
2269 new file mode 100644
2270 index 0000000..ad71473
2271 --- /dev/null
2272 +++ b/test/data/valid-config-files/check-1.conf
2273 @@ -0,0 +1,9 @@
2274 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2275 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2276 +<busconfig>
2277 +  <user>mybususer</user>
2278 +  <listen>unix:path=/foo/bar</listen>
2279 +  <policy context="default">
2280 +    <check privilege="foo" send_destination="*"/>
2281 +  </policy>
2282 +</busconfig>
2283 diff --git a/test/data/valid-config-files/debug-check-some.conf.in b/test/data/valid-config-files/debug-check-some.conf.in
2284 new file mode 100644
2285 index 0000000..47ee854
2286 --- /dev/null
2287 +++ b/test/data/valid-config-files/debug-check-some.conf.in
2288 @@ -0,0 +1,18 @@
2289 +<!-- Bus that listens on a debug pipe and doesn't create any restrictions -->
2290 +
2291 +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
2292 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2293 +<busconfig>
2294 +  <listen>debug-pipe:name=test-server</listen>
2295 +  <listen>@TEST_LISTEN@</listen>
2296 +  <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
2297 +  <policy context="default">
2298 +    <allow send_interface="*"/>
2299 +    <allow receive_interface="*"/>
2300 +    <allow own="*"/>
2301 +    <allow user="*"/>
2302 +
2303 +    <deny send_interface="org.freedesktop.TestSuite" send_member="Echo"/>
2304 +    <check privilege="foo" send_interface="org.freedesktop.TestSuite" send_member="Echo"/>
2305 +  </policy>
2306 +</busconfig>
2307 -- 
2308 2.21.1
2309