bus/connection: don't check cmdline in session dbus-daemon
[platform/upstream/dbus.git] / bus / connection.c
index 050bf8e..6b85ba3 100644 (file)
@@ -41,6 +41,7 @@
 #ifdef DBUS_ENABLE_CYNARA
 #include <stdlib.h>
 #include <cynara-session.h>
+#include <stdio.h>
 #endif
 
 /* Trim executed commands to this length; we want to keep logs readable */
@@ -117,6 +118,7 @@ typedef struct
 #ifdef DBUS_ENABLE_STATS
   int peak_match_rules;
   int peak_bus_names;
+  int peak_pending_replies;
 #endif
   int n_pending_unix_fds;
   DBusTimeout *pending_unix_fds_timeout;
@@ -453,9 +455,6 @@ free_connection_data (void *data)
   if (d->policy)
     bus_client_policy_unref (d->policy);
 
-  if (d->selinux_id)
-    bus_selinux_id_unref (d->selinux_id);
-
   if (d->apparmor_confinement)
     bus_apparmor_confinement_unref (d->apparmor_confinement);
   
@@ -592,6 +591,13 @@ bus_connections_unref (BusConnections *connections)
     }
 }
 
+static dbus_bool_t
+is_context_type_session (BusConnectionData *d)
+{
+  const char *context_type = bus_context_get_type (d->connections->context);
+  return context_type && !strcmp (context_type, "session");
+}
+
 /* Used for logging */
 static dbus_bool_t
 cache_peer_loginfo_string (BusConnectionData *d, 
@@ -600,7 +606,7 @@ cache_peer_loginfo_string (BusConnectionData *d,
   DBusString loginfo_buf;
   unsigned long uid;
   unsigned long pid;
-  char *windows_sid;
+  char *windows_sid = NULL, *security_label = NULL;
   dbus_bool_t prev_added;
 
   if (!_dbus_string_init (&loginfo_buf))
@@ -625,20 +631,63 @@ cache_peer_loginfo_string (BusConnectionData *d,
       if (!_dbus_string_append_printf (&loginfo_buf, "pid=%ld comm=\"", pid))
         goto oom;
       /* Ignore errors here; we may not have permissions to read the
-       * proc file. */
-      //_dbus_command_for_pid (pid, &loginfo_buf, MAX_LOG_COMMAND_LEN, NULL);
+       * proc file.
+       * Don't even try it for the session daemon, to avoid cluttering logs with security error logs for
+       * accessing the proc file.
+       */
+      if (!is_context_type_session(d))
+        {
+          _dbus_command_for_pid (pid, &loginfo_buf, MAX_LOG_COMMAND_LEN, NULL);
+        }
+      else
+        {
+          if (!_dbus_string_append (&loginfo_buf, "<not-read>"))   /* for session daemon just say that we didn't try */
+            goto oom;
+        }
       if (!_dbus_string_append_byte (&loginfo_buf, '"'))
         goto oom;
+      else
+        prev_added = TRUE;
     }
 
   if (dbus_connection_get_windows_user (connection, &windows_sid))
     {
       dbus_bool_t did_append;
+
+      if (prev_added)
+        {
+          if (!_dbus_string_append_byte (&loginfo_buf, ' '))
+            goto oom;
+        }
+
       did_append = _dbus_string_append_printf (&loginfo_buf,
-                                               "sid=\"%s\" ", windows_sid);
+                                               "sid=\"%s\"", windows_sid);
       dbus_free (windows_sid);
+      windows_sid = NULL;
       if (!did_append)
         goto oom;
+      else
+        prev_added = TRUE;
+    }
+
+  if (_dbus_connection_get_linux_security_label (connection, &security_label))
+    {
+      dbus_bool_t did_append;
+
+      if (prev_added)
+        {
+          if (!_dbus_string_append_byte (&loginfo_buf, ' '))
+            goto oom;
+        }
+
+      did_append = _dbus_string_append_printf (&loginfo_buf,
+                                               "label=\"%s\"", security_label);
+      dbus_free (security_label);
+      security_label = NULL;
+      if (!did_append)
+        goto oom;
+      else
+        prev_added = TRUE;
     }
 
   if (!_dbus_string_steal_data (&loginfo_buf, &(d->cached_loginfo_string)))
@@ -649,6 +698,11 @@ cache_peer_loginfo_string (BusConnectionData *d,
   return TRUE;
 oom:
    _dbus_string_free (&loginfo_buf);
+   if (security_label != NULL)
+     dbus_free (security_label);
+   if (windows_sid != NULL)
+     dbus_free (windows_sid);
+
    return FALSE;
 }
 
@@ -686,6 +740,18 @@ static dbus_bool_t
 pending_unix_fds_timeout_cb (void *data)
 {
   DBusConnection *connection = data;
+  BusConnectionData *d = BUS_CONNECTION_DATA (connection);
+  int limit;
+
+  _dbus_assert (d != NULL);
+  limit = bus_context_get_pending_fd_timeout (d->connections->context);
+  bus_context_log (d->connections->context, DBUS_SYSTEM_LOG_WARNING,
+      "Connection \"%s\" (%s) has had Unix fds pending for too long, "
+      "closing it (pending_fd_timeout=%d ms)",
+      d->name != NULL ? d->name : "(null)",
+      bus_connection_get_loginfo (connection),
+      limit);
+
   dbus_connection_close (connection);
   return TRUE;
 }
@@ -695,15 +761,13 @@ bus_connections_setup_connection (BusConnections *connections,
                                   DBusConnection *connection)
 {
 
-  BusConnectionData *d;
-  dbus_bool_t retval;
+  BusConnectionData *d = NULL;
   DBusError error;
 
-  
   d = dbus_new0 (BusConnectionData, 1);
   
   if (d == NULL)
-    return FALSE;
+    goto oom;
 
   d->connections = connections;
   d->connection = connection;
@@ -717,39 +781,35 @@ bus_connections_setup_connection (BusConnections *connections,
                                  connection_data_slot,
                                  d, free_connection_data))
     {
+      /* We have to free d explicitly, because this is the only code
+       * path where it's non-NULL but dbus_connection_set_data() hasn't
+       * taken responsibility for freeing it. */
       dbus_free (d);
-      return FALSE;
+      d = NULL;
+      goto oom;
     }
 
   dbus_connection_set_route_peer_messages (connection, TRUE);
-  
-  retval = FALSE;
 
   dbus_error_init (&error);
   d->selinux_id = bus_selinux_init_connection_id (connection,
                                                   &error);
   if (dbus_error_is_set (&error))
     {
-      /* This is a bit bogus because we pretend all errors
-       * are OOM; this is done because we know that in bus.c
-       * an OOM error disconnects the connection, which is
-       * the same thing we want on any other error.
-       */
+      bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING,
+                       "Unable to set up new connection: %s", error.message);
       dbus_error_free (&error);
-      goto out;
+      goto error;
     }
 
   d->apparmor_confinement = bus_apparmor_init_connection_confinement (connection,
                                                                       &error);
   if (dbus_error_is_set (&error))
     {
-      /* This is a bit bogus because we pretend all errors
-       * are OOM; this is done because we know that in bus.c
-       * an OOM error disconnects the connection, which is
-       * the same thing we want on any other error.
-       */
+      bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING,
+                       "Unable to set up new connection: %s", error.message);
       dbus_error_free (&error);
-      goto out;
+      goto error;
     }
 
   if (!dbus_connection_set_watch_functions (connection,
@@ -758,14 +818,14 @@ bus_connections_setup_connection (BusConnections *connections,
                                             toggle_connection_watch,
                                             connection,
                                             NULL))
-    goto out;
+    goto oom;
   
   if (!dbus_connection_set_timeout_functions (connection,
                                               add_connection_timeout,
                                               remove_connection_timeout,
                                               NULL,
                                               connection, NULL))
-    goto out;
+    goto oom;
 
   /* For now we don't need to set a Windows user function because
    * there are no policies in the config file controlling what
@@ -783,18 +843,18 @@ bus_connections_setup_connection (BusConnections *connections,
 
   d->link_in_connection_list = _dbus_list_alloc_link (connection);
   if (d->link_in_connection_list == NULL)
-    goto out;
+    goto oom;
   
   /* Setup the connection with the dispatcher */
   if (!bus_dispatch_add_connection (connection))
-    goto out;
+    goto oom;
 
   if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
     {
       if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection))
         {
           bus_dispatch_remove_connection (connection);
-          goto out;
+          goto oom;
         }
     }
 
@@ -803,12 +863,12 @@ bus_connections_setup_connection (BusConnections *connections,
                                                    pending_unix_fds_timeout_cb,
                                                    connection, NULL);
   if (d->pending_unix_fds_timeout == NULL)
-    goto out;
+    goto oom;
 
   _dbus_timeout_disable (d->pending_unix_fds_timeout);
   if (!_dbus_loop_add_timeout (bus_context_get_loop (connections->context),
                                d->pending_unix_fds_timeout))
-    goto out;
+    goto oom;
 
   _dbus_connection_set_pending_fds_function (connection,
           (DBusPendingFdsChangeFunction) check_pending_fds_cb,
@@ -831,13 +891,15 @@ bus_connections_setup_connection (BusConnections *connections,
    * stop accept()ing any more, to avert a DoS. See fd.o #80919 */
   bus_context_check_all_watches (d->connections->context);
   
-  retval = TRUE;
+  return TRUE;
 
- out:
-  if (!retval)
+oom:
+  bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING,
+                   "No memory to set up new connection");
+  /* fall through */
+error:
+  if (d != NULL)
     {
-      if (d->selinux_id)
-        bus_selinux_id_unref (d->selinux_id);
       d->selinux_id = NULL;
 
       if (d->apparmor_confinement)
@@ -888,7 +950,7 @@ bus_connections_setup_connection (BusConnections *connections,
       /* "d" has now been freed */
     }
   
-  return retval;
+  return FALSE;
 }
 
 void
@@ -1063,6 +1125,11 @@ const char *bus_connection_get_cynara_session_id (DBusConnection *connection)
       unsigned long pid;
       if (dbus_connection_get_unix_process_id(connection, &pid))
         d->cynara_session_id = cynara_session_from_pid(pid);
+
+      /* If client exits as soon as async call, cynara_session_from_pid() returns null.
+         cynara_session_from_pid checks /proc/pid to verify process */
+      if (d->cynara_session_id == NULL)
+        asprintf (&d->cynara_session_id, "/proc/%ld", pid);
     }
   return d->cynara_session_id;
 }
@@ -1452,6 +1519,45 @@ bus_connection_get_n_match_rules (DBusConnection *connection)
   return d->n_match_rules;
 }
 
+dbus_bool_t
+bus_connection_is_service_owner_by_prefix (DBusConnection *connection,
+                                           const char *name_prefix)
+{
+  BusConnectionData *d;
+  DBusList *link;
+
+  d = BUS_CONNECTION_DATA (connection);
+  _dbus_assert (d != NULL);
+
+  link = _dbus_list_get_first_link (&d->services_owned);
+  while (link != NULL)
+    {
+      BusService *service = link->data;
+      DBusString str;
+
+      _dbus_string_init_const (&str, bus_service_get_name (service));
+
+      if (_dbus_string_starts_with_words_c_str (&str, name_prefix, '.'))
+        return TRUE;
+
+      link = _dbus_list_get_next_link (&d->services_owned, link);
+    }
+
+  return FALSE;
+}
+
+const DBusList *
+bus_connection_get_owned_services_list (DBusConnection *connection)
+{
+  BusConnectionData *d;
+
+  d = BUS_CONNECTION_DATA (connection);
+
+  _dbus_assert (d != NULL);
+
+  return d->services_owned;
+}
+
 void
 bus_connection_add_owned_service_link (DBusConnection *connection,
                                        DBusList       *link)
@@ -1664,13 +1770,23 @@ bus_connection_get_name (DBusConnection *connection)
 dbus_bool_t
 bus_connections_check_limits (BusConnections  *connections,
                               DBusConnection  *requesting_completion,
+                              const char     **limit_name_out,
+                              int             *limit_out,
                               DBusError       *error)
 {
   unsigned long uid;
+  int limit;
+
+  limit = bus_context_get_max_completed_connections (connections->context);
 
-  if (connections->n_completed >=
-      bus_context_get_max_completed_connections (connections->context))
+  if (connections->n_completed >= limit)
     {
+      if (limit_name_out != NULL)
+        *limit_name_out = "max_completed_connections";
+
+      if (limit_out != NULL)
+        *limit_out = limit;
+
       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
                       "The maximum number of active connections has been reached");
       return FALSE;
@@ -1678,9 +1794,16 @@ bus_connections_check_limits (BusConnections  *connections,
   
   if (dbus_connection_get_unix_user (requesting_completion, &uid))
     {
-      if (get_connections_for_uid (connections, uid) >=
-          bus_context_get_max_connections_per_user (connections->context))
+      limit = bus_context_get_max_connections_per_user (connections->context);
+
+      if (get_connections_for_uid (connections, uid) >= limit)
         {
+          if (limit_name_out != NULL)
+            *limit_name_out = "max_connections_per_user";
+
+          if (limit_out != NULL)
+            *limit_out = limit;
+
           dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
                           "The maximum number of active connections for UID %lu has been reached",
                           uid);
@@ -1900,6 +2023,7 @@ bus_connections_expect_reply (BusConnections  *connections,
   DBusList *link;
   CancelPendingReplyData *cprd;
   int count;
+  int limit;
 
   _dbus_assert (will_get_reply != NULL);
   _dbus_assert (will_send_reply != NULL);
@@ -1930,15 +2054,35 @@ bus_connections_expect_reply (BusConnections  *connections,
       if (pending->will_get_reply == will_get_reply)
         ++count;
     }
-  
-  if (count >=
-      bus_context_get_max_replies_per_connection (connections->context))
+
+  limit = bus_context_get_max_replies_per_connection (connections->context);
+
+  if (count >= limit)
     {
+      bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING,
+                       "The maximum number of pending replies for "
+                       "\"%s\" (%s) has been reached "
+                       "(max_replies_per_connection=%d)",
+                       bus_connection_get_name (will_get_reply),
+                       bus_connection_get_loginfo (will_get_reply),
+                       limit);
+
       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
                      "The maximum number of pending replies per connection has been reached");
       return FALSE;
     }
 
+#ifdef DBUS_ENABLE_STATS
+  {
+    BusConnectionData *d;
+
+    d = BUS_CONNECTION_DATA (will_get_reply);
+    _dbus_assert (d != NULL);
+
+    update_peak(&d->peak_pending_replies, count);
+  }
+#endif
+
   pending = dbus_new0 (BusPendingReply, 1);
   if (pending == NULL)
     {
@@ -2213,6 +2357,7 @@ bus_transaction_get_context (BusTransaction  *transaction)
 dbus_bool_t
 bus_transaction_capture (BusTransaction *transaction,
                          DBusConnection *sender,
+                         DBusConnection *addressed_recipient,
                          DBusMessage    *message)
 {
   BusConnections *connections;
@@ -2232,8 +2377,8 @@ bus_transaction_capture (BusTransaction *transaction,
    * There's little point, since there is up to 1 per process. */
   _dbus_assert (mm != NULL);
 
-  if (!bus_matchmaker_get_recipients (mm, connections, sender, NULL, message,
-        &recipients))
+  if (!bus_matchmaker_get_recipients (mm, connections, sender,
+        addressed_recipient, message, &recipients))
     goto out;
 
   for (link = _dbus_list_get_first_link (&recipients);
@@ -2255,6 +2400,7 @@ out:
 
 dbus_bool_t
 bus_transaction_capture_error_reply (BusTransaction  *transaction,
+                                     DBusConnection  *addressed_recipient,
                                      const DBusError *error,
                                      DBusMessage     *in_reply_to)
 {
@@ -2281,7 +2427,7 @@ bus_transaction_capture_error_reply (BusTransaction  *transaction,
   if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
     goto out;
 
-  ret = bus_transaction_capture (transaction, NULL, reply);
+  ret = bus_transaction_capture (transaction, NULL, addressed_recipient, reply);
 
 out:
   dbus_message_unref (reply);
@@ -2294,7 +2440,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
                                   DBusMessage    *message)
 {
   DBusError error = DBUS_ERROR_INIT;
-  BusDeferredMessage *deferred_message;
+  BusDeferredMessage *deferred_message = NULL;
 
   /* We have to set the sender to the driver, and have
    * to check security policy since it was not done in
@@ -2324,7 +2470,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
   /* Capture it for monitors, even if the real recipient's receive policy
    * does not allow it to receive this message from us (which would be odd).
    */
-  if (!bus_transaction_capture (transaction, NULL, message))
+  if (!bus_transaction_capture (transaction, NULL, connection, message))
     return FALSE;
 
   /* If security policy doesn't allow the message, we would silently
@@ -2334,13 +2480,15 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
    */
   switch (bus_context_check_security_policy (bus_transaction_get_context (transaction),
                                              transaction,
-                                             NULL, connection, connection, message, &error,
+                                             NULL, connection, connection,
+                                             message, NULL, &error,
                                              &deferred_message))
     {
     case BUS_RESULT_TRUE:
       break;
     case BUS_RESULT_FALSE:
-      if (!bus_transaction_capture_error_reply (transaction, &error, message))
+      if (!bus_transaction_capture_error_reply (transaction, connection,
+                                                &error, message))
         {
           bus_context_log (transaction->context, DBUS_SYSTEM_LOG_WARNING,
                            "message from dbus-daemon rejected but not enough "
@@ -2682,6 +2830,9 @@ dbus_bool_t
 bus_connection_has_deferred_messages (DBusConnection *connection)
 {
   BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+
+  _dbus_assert (d != NULL);
+
   return d->deferred_messages != NULL ? TRUE : FALSE;
 }
 
@@ -2692,6 +2843,9 @@ bus_connection_queue_deferred_message (DBusConnection *connection,
 {
   BusConnectionData *d = BUS_CONNECTION_DATA(connection);
   dbus_bool_t success;
+
+  _dbus_assert (d != NULL);
+
   if (prepend)
     success = _dbus_list_prepend(&d->deferred_messages, message);
   else
@@ -2706,27 +2860,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);
-
-  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)
 {
@@ -2734,6 +2867,8 @@ bus_connection_pop_deferred_message (DBusConnection *connection)
   BusDeferredMessage *message;
   BusConnectionData *d = BUS_CONNECTION_DATA(connection);
 
+  _dbus_assert (d != NULL);
+
   link =_dbus_list_get_first_link(&d->deferred_messages);
   if (link != NULL)
     {
@@ -2752,6 +2887,9 @@ dbus_bool_t
 bus_connection_putback_deferred_message (DBusConnection *connection, BusDeferredMessage *message)
 {
   BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+
+  _dbus_assert (d != NULL);
+
   if (_dbus_list_prepend(&d->deferred_messages, message))
     {
       return TRUE;
@@ -2767,6 +2905,8 @@ bus_connection_clear_deferred_messages (DBusConnection *connection)
   DBusList *next;
   BusDeferredMessage *message;
 
+  _dbus_assert (d != NULL);
+
   link =_dbus_list_get_first_link(&d->deferred_messages);
   while (link != NULL)
     {
@@ -2785,6 +2925,9 @@ bus_connection_remove_deferred_message (DBusConnection *connection,
                                         BusDeferredMessage *message)
 {
   BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+
+  _dbus_assert (d != NULL);
+
   if (_dbus_list_remove(&d->deferred_messages, message))
     bus_deferred_message_unref(message);
 }
@@ -2859,6 +3002,40 @@ bus_connection_get_peak_bus_names (DBusConnection *connection)
 
   return d->peak_bus_names;
 }
+
+int bus_connection_get_n_pending_replies (DBusConnection *connection)
+{
+  BusConnectionData *d;
+  DBusList *link;
+  BusPendingReply *pending;
+  int count = 0;
+
+  d = BUS_CONNECTION_DATA (connection);
+  _dbus_assert(d != NULL);
+
+  link = bus_expire_list_get_first_link(d->connections->pending_replies);
+  while (link != NULL)
+    {
+      pending = link->data;
+      link = bus_expire_list_get_next_link(d->connections->pending_replies,
+        link);
+      if (pending->will_get_reply == connection)
+        ++count;
+    }
+
+  return count;
+}
+
+int
+bus_connection_get_peak_pending_replies (DBusConnection *connection)
+{
+  BusConnectionData *d;
+
+  d = BUS_CONNECTION_DATA (connection);
+  _dbus_assert (d != NULL);
+
+  return d->peak_pending_replies;
+}
 #endif /* DBUS_ENABLE_STATS */
 
 dbus_bool_t