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