cynara integration: check policy right away for both send and receive 10/244110/2
authorAdrian Szyndela <adrian.s@samsung.com>
Mon, 14 Sep 2020 11:06:02 +0000 (13:06 +0200)
committerAdrian Szyndela <adrian.s@samsung.com>
Tue, 15 Sep 2020 06:41:30 +0000 (08:41 +0200)
Check policy at moments, when sender is still present, so the policy
can be checked for both sender and receiver.

This way only potential waiting for cynara check is left with no need
to access any connection data.

Change-Id: I6544740c6e31dee286261fe3cddb3f692c669c4d

bus/bus.c
bus/check.c
bus/check.h
bus/connection.c
bus/connection.h
bus/cynara.c
bus/dispatch.c

index eb932f6..288832b 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -1563,6 +1563,7 @@ bus_context_check_security_policy (BusContext          *context,
   dbus_bool_t requested_reply;
   const char *privilege;
   char *out_rule = NULL;
+  BusResult can_send_result;
 
   type = dbus_message_get_type (message);
   src = dbus_message_get_sender (message);
@@ -1748,18 +1749,16 @@ bus_context_check_security_policy (BusContext          *context,
 
   log = FALSE;
   if (sender_policy) {
-    switch (bus_client_policy_check_can_send (sender,
-                                              sender_policy,
-                                              context->registry,
-                                              requested_reply,
-                                              addressed_recipient,
-                                              proposed_recipient,
-                                              message, &toggles, &log, &privilege,
-                                              deferred_message, &out_rule))
+    can_send_result = bus_client_policy_check_can_send (sender,
+                                                        sender_policy,
+                                                        context->registry,
+                                                        requested_reply,
+                                                        addressed_recipient,
+                                                        proposed_recipient,
+                                                        message, &toggles, &log, &privilege,
+                                                        deferred_message, &out_rule);
+    if (can_send_result == BUS_RESULT_FALSE)
       {
-      case BUS_RESULT_TRUE:
-        break;
-      case BUS_RESULT_FALSE:
         complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
                                 "Rejected send message", toggles,
                                 message, sender, proposed_recipient, requested_reply,
@@ -1770,10 +1769,6 @@ bus_context_check_security_policy (BusContext          *context,
         if (out_rule)
           free (out_rule);
         return BUS_RESULT_FALSE;
-        break;
-      case BUS_RESULT_LATER:
-        return BUS_RESULT_LATER;
-        break;
       }
   }
 
@@ -1807,12 +1802,17 @@ bus_context_check_security_policy (BusContext          *context,
             "security policy disallowing message due to recipient policy\n");
         if (out_rule)
           free (out_rule);
+        if (deferred_message && *deferred_message)
+          bus_deferred_message_set_response (*deferred_message, BUS_RESULT_FALSE);
         return BUS_RESULT_FALSE;
       case BUS_RESULT_LATER:
         return BUS_RESULT_LATER;
       }
   }
 
+  if (can_send_result == BUS_RESULT_LATER)
+    return BUS_RESULT_LATER;
+
   /* See if limits on size have been exceeded */
   if (!bus_context_check_recipient_message_limits(context, proposed_recipient, sender, message,
       requested_reply, error))
index 0f3c8ed..2221f71 100644 (file)
@@ -130,6 +130,7 @@ bus_check_get_cynara (BusCheck *check)
 
 static void
 bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
+                                    BusDeferredMessageStatus check_type,
                                     BusResult result)
 {
   _dbus_verbose("bus_check_enable_dispatch_callback called deferred_message=%p\n", deferred_message);
@@ -140,53 +141,23 @@ bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
 
 static void
 bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
+                                         BusDeferredMessageStatus check_type,
                                          BusResult result)
 {
-  int status;
-
   _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
 
   if (!(dbus_connection_get_is_connected(deferred_message->proposed_recipient)
                          && bus_connection_is_active(deferred_message->proposed_recipient)))
     return;
 
-  status = deferred_message->status;
-
-  deferred_message->status = 0; /* mark message as not waiting for response */
-  deferred_message->response = result;
+  deferred_message->status &= ~check_type; /* mark message as not waiting for response of this type*/
+  if (deferred_message->response != BUS_RESULT_FALSE)
+    deferred_message->response = result;
 
-  /*
-   * If send rule allows us to send message we still need to check receive rules.
-   */
-  if ((status & BUS_DEFERRED_MESSAGE_CHECK_SEND) && (result == BUS_RESULT_TRUE))
-    {
-      int toggles;
-      BusContext *context;
-      BusRegistry *registry;
-      BusClientPolicy *recipient_policy;
-      BusDeferredMessage *deferred_message_receive = NULL;
-
-      context = bus_connection_get_context(deferred_message->proposed_recipient);
-      registry = bus_context_get_registry(context);
-      recipient_policy = bus_connection_get_policy(deferred_message->proposed_recipient);
-
-      deferred_message->response = bus_client_policy_check_can_receive(recipient_policy, registry,
-          deferred_message->requested_reply, deferred_message->sender,
-          deferred_message->addressed_recipient, deferred_message->proposed_recipient, deferred_message->message,
-          &toggles, NULL, &deferred_message_receive, NULL);
-      if (deferred_message->response == BUS_RESULT_LATER)
-        {
-          /* replace deferred message associated with send check with the one associated with
-           * receive check */
-          if (!bus_deferred_message_replace(deferred_message, deferred_message_receive))
-            {
-              /* failed to replace deferred message (due to oom). Set it to rejected */
-              deferred_message->response = BUS_RESULT_FALSE;
-            }
-        }
-    }
+  _dbus_assert (deferred_message->response != BUS_RESULT_LATER || deferred_message->status != 0);
 
-  bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
+  if (!deferred_message->status)
+    bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
 }
 
 static void
@@ -406,6 +377,8 @@ bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, B
   int type = dbus_message_get_type(deferred_message->message);
   if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
         deferred_message->sender &&
+        dbus_connection_get_is_connected(deferred_message->sender) &&
+        bus_connection_is_active(deferred_message->sender) &&
         deferred_message->addressed_recipient &&
         deferred_message->addressed_recipient == deferred_message->proposed_recipient && /* not eavesdropping */
         !bus_connections_expect_reply (bus_connection_get_connections (deferred_message->sender),
@@ -495,14 +468,6 @@ bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
       goto out;
     }
 
-  /* do not attempt to send message if sender has disconnected */
-  if (deferred_message->sender != NULL && !(dbus_connection_get_is_connected(deferred_message->sender) && bus_connection_is_active(deferred_message->sender)))
-    {
-      bus_transaction_cancel_and_free(transaction);
-      result = BUS_RESULT_FALSE;
-      goto out;
-    }
-
   result = bus_dispatch_matches(transaction, deferred_message->sender,
       deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
 
@@ -567,19 +532,6 @@ out:
 }
 
 dbus_bool_t
-bus_deferred_message_replace (BusDeferredMessage *old_message, BusDeferredMessage *new_message)
-{
-  if (bus_connection_replace_deferred_message(old_message->proposed_recipient,
-        old_message, new_message))
-    {
-      new_message->response_callback = old_message->response_callback;
-      new_message->full_dispatch = old_message->full_dispatch;
-      return TRUE;
-    }
-  return FALSE;
-}
-
-dbus_bool_t
 bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
 {
   return deferred_message->status != 0;
@@ -604,12 +556,19 @@ bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
 }
 
 void
+bus_deferred_message_set_response (BusDeferredMessage *deferred_message, BusResult response)
+{
+  return deferred_message->response = response;
+}
+
+void
 bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
+                                        BusDeferredMessageStatus check_type,
                                         BusResult result)
 {
   if (deferred_message->response_callback != NULL)
     {
-      deferred_message->response_callback(deferred_message, result);
+      deferred_message->response_callback(deferred_message, check_type, result);
     }
 }
 
index 3c6b2a1..5cf9099 100644 (file)
 #include "policy.h"
 
 
-typedef void (*BusCheckResponseFunc) (BusDeferredMessage *message,
-                                      BusResult result);
-
 typedef enum {
   BUS_DEFERRED_MESSAGE_CHECK_SEND      = 1 << 0,
   BUS_DEFERRED_MESSAGE_CHECK_RECEIVE   = 1 << 1,
   BUS_DEFERRED_MESSAGE_CHECK_OWN       = 1 << 2,
 } BusDeferredMessageStatus;
 
+typedef void (*BusCheckResponseFunc) (BusDeferredMessage *message,
+                                      BusDeferredMessageStatus check_type,
+                                      BusResult result);
 
 BusCheck   *bus_check_new         (BusContext *context,
                                    DBusError *error);
@@ -68,15 +68,16 @@ BusResult           bus_deferred_message_dispatch           (BusDeferredMessage
 dbus_bool_t         bus_deferred_message_waits_for_check    (BusDeferredMessage *deferred_message);
 DBusConnection     *bus_deferred_message_get_recipient      (BusDeferredMessage *deferred_message);
 void                bus_deferred_message_response_received  (BusDeferredMessage *deferred_message,
+                                                             BusDeferredMessageStatus check_type,
                                                              BusResult result);
 dbus_bool_t         bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
                                                              BusTransaction *transaction,
                                                              dbus_bool_t full_dispatch,
                                                              dbus_bool_t prepend);
-dbus_bool_t         bus_deferred_message_replace            (BusDeferredMessage *old_message,
-                                                             BusDeferredMessage *new_message);
 void                bus_deferred_message_disable_sender     (BusDeferredMessage *deferred_message);
 BusResult           bus_deferred_message_get_response       (BusDeferredMessage *deferred_message);
+void                bus_deferred_message_set_response       (BusDeferredMessage *deferred_message,
+                                                             BusResult response);
 
 BusDeferredMessageStatus  bus_deferred_message_get_status   (BusDeferredMessage *deferred_message);
 
index dcb47ba..89cf979 100644 (file)
@@ -2842,29 +2842,6 @@ bus_connection_queue_deferred_message (DBusConnection *connection,
   return FALSE;
 }
 
-dbus_bool_t
-bus_connection_replace_deferred_message (DBusConnection *connection,
-                                         BusDeferredMessage *oldMessage,
-                                         BusDeferredMessage *newMessage)
-{
-  DBusList *link;
-  BusConnectionData *d = BUS_CONNECTION_DATA(connection);
-
-  _dbus_assert (d != NULL);
-
-  link = _dbus_list_find_first(&d->deferred_messages, oldMessage);
-  if (link == NULL)
-    return FALSE;
-
-  if (!_dbus_list_insert_after(&d->deferred_messages, link, newMessage))
-    return FALSE;
-
-  bus_deferred_message_ref(newMessage);
-  _dbus_list_remove_link(&d->deferred_messages, link);
-  bus_deferred_message_unref(oldMessage);
-  return TRUE;
-}
-
 BusDeferredMessage *
 bus_connection_pop_deferred_message (DBusConnection *connection)
 {
index 85607be..acaee15 100644 (file)
@@ -94,9 +94,6 @@ dbus_bool_t         bus_connection_putback_deferred_message (DBusConnection *con
                                                              BusDeferredMessage *message);
 void                bus_connection_remove_deferred_message  (DBusConnection *connection,
                                                              BusDeferredMessage *message);
-dbus_bool_t         bus_connection_replace_deferred_message (DBusConnection *connection,
-                                                             BusDeferredMessage *oldMessage,
-                                                             BusDeferredMessage *newMessage);
 void                bus_connection_dispatch_deferred        (DBusConnection *connection);
 void                bus_connection_clear_deferred_messages  (DBusConnection *connection);
 
index 98255cd..cdcc5da 100644 (file)
@@ -49,6 +49,12 @@ typedef struct BusCynara
   DBusWatch    *cynara_watch;
 } BusCynara;
 
+typedef struct BusCynaraCheckData
+{
+  BusDeferredMessage *deferred_message;
+  BusDeferredMessageStatus check_type;
+} BusCynaraCheckData;
+
 static dbus_bool_t bus_cynara_watch_callback(DBusWatch *watch,
                                              unsigned int flags,
                                              void *data);
@@ -63,6 +69,20 @@ static void bus_cynara_check_response_callback (cynara_check_id check_id,
                                                 void *user_response_data);
 #endif
 
+static BusCynaraCheckData *
+bus_cynara_check_data_new(BusDeferredMessage *deferred_message, BusDeferredMessageStatus check_type)
+{
+  BusCynaraCheckData *data;
+
+  data = dbus_new(BusCynaraCheckData, 1);
+  if (data == NULL)
+    return NULL;
+
+  data->deferred_message = deferred_message;
+  data->check_type = check_type;
+
+  return data;
+}
 
 BusCynara *
 bus_cynara_new(BusCheck *check, DBusError *error)
@@ -148,8 +168,9 @@ bus_cynara_check_privilege (BusCynara *cynara,
   char user[32];
   cynara_check_id check_id;
   DBusConnection *connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
-  BusDeferredMessage *deferred_message;
+  BusDeferredMessage *deferred_message = NULL;
   BusResult return_result;
+  BusCynaraCheckData *callback_data;
 
   _dbus_assert(connection != NULL);
 
@@ -208,9 +229,16 @@ bus_cynara_check_privilege (BusCynara *cynara,
         bus_deferred_message_ref(deferred_message);
       }
 
-    /* callback is supposed to unref deferred_message*/
+    callback_data = bus_cynara_check_data_new(deferred_message, check_type);
+    if (callback_data == NULL)
+      {
+           _dbus_verbose("Failed to allocate memory for deferred message callback data\n");
+           return_result = BUS_RESULT_FALSE;
+      }
+
+    /* callback is supposed to unref deferred_message and free callback_data */
     result = cynara_async_create_request(cynara->cynara, label, session_id, user, privilege, &check_id,
-        &bus_cynara_check_response_callback, deferred_message);
+        &bus_cynara_check_response_callback, callback_data);
     if (result == CYNARA_API_SUCCESS)
       {
         _dbus_verbose("Created Cynara request: client=%s session_id=%s user=%s privilege=%s check_id=%u "
@@ -336,12 +364,22 @@ bus_cynara_check_response_callback (cynara_check_id check_id,
                                     int response,
                                     void *user_response_data)
 {
-  BusDeferredMessage *deferred_message = user_response_data;
+  BusCynaraCheckData *check_data = user_response_data;
+  BusDeferredMessage *deferred_message;
   BusResult result;
+  BusDeferredMessageStatus check_type;
 
   _dbus_verbose("Cynara callback: check_id=%u, cause=%s response=%i response_data=%p\n",
       (unsigned int)check_id, call_cause_to_string(cause), response, user_response_data);
 
+  if (check_data == NULL)
+    return;
+
+  deferred_message = check_data->deferred_message;
+  check_type = check_data->check_type;
+
+  dbus_free(check_data);
+
   if (deferred_message == NULL)
     return;
 
@@ -350,7 +388,7 @@ bus_cynara_check_response_callback (cynara_check_id check_id,
   else
     result = BUS_RESULT_FALSE;
 
-  bus_deferred_message_response_received(deferred_message, result);
+  bus_deferred_message_response_received(deferred_message, check_type, result);
   bus_deferred_message_unref(deferred_message);
 }
 
index 9d2e893..d829296 100644 (file)
@@ -151,7 +151,11 @@ bus_dispatch_matches (BusTransaction     *transaction,
    * or for signals with no particular recipient
    */
 
-  _dbus_assert (sender == NULL || bus_connection_is_active (sender));
+  /*
+   * With deferred messages, dispatch may happen when there is no sender anymore.
+   * Policy rules involving the sender should be checked before, anyway.
+   */
+/*  _dbus_assert (sender == NULL || bus_connection_is_active (sender)); */
   _dbus_assert (dbus_message_get_sender (message) != NULL);
 
   context = bus_transaction_get_context (transaction);
@@ -165,8 +169,15 @@ bus_dispatch_matches (BusTransaction     *transaction,
        */
       if (dispatched_deferred_message == NULL && bus_connection_has_deferred_messages(addressed_recipient))
         {
-          deferred_message = bus_deferred_message_new(message, sender,
-              addressed_recipient, addressed_recipient, BUS_RESULT_LATER);
+          result = bus_context_check_security_policy(context, transaction,
+              sender, addressed_recipient, addressed_recipient, message, NULL, error,
+              &deferred_message);
+
+          if (deferred_message == NULL)
+            deferred_message = bus_deferred_message_new(message, sender,
+                  addressed_recipient, addressed_recipient, result);
+          else
+            bus_deferred_message_ref(deferred_message);
 
           if (deferred_message == NULL)
             {