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