Clarify license declaration
[platform/upstream/dbus.git] / bus / driver.c
index 379a47e..1d05eab 100644 (file)
@@ -68,11 +68,12 @@ bus_driver_get_owner_of_name (DBusConnection *connection,
   return bus_service_get_primary_owners_connection (serv);
 }
 
-static DBusConnection *
+BusDriverFound
 bus_driver_get_conn_helper (DBusConnection  *connection,
                             DBusMessage     *message,
                             const char      *what_we_want,
                             const char     **name_p,
+                            DBusConnection **peer_conn_p,
                             DBusError       *error)
 {
   DBusConnection *conn;
@@ -81,11 +82,17 @@ bus_driver_get_conn_helper (DBusConnection  *connection,
   if (!dbus_message_get_args (message, error,
                               DBUS_TYPE_STRING, &name,
                               DBUS_TYPE_INVALID))
-    return NULL;
+    return BUS_DRIVER_FOUND_ERROR;
 
   _dbus_assert (name != NULL);
   _dbus_verbose ("asked for %s of connection %s\n", what_we_want, name);
 
+  if (name_p != NULL)
+    *name_p = name;
+
+  if (strcmp (name, DBUS_SERVICE_DBUS) == 0)
+    return BUS_DRIVER_FOUND_SELF;
+
   conn = bus_driver_get_owner_of_name (connection, name);
 
   if (conn == NULL)
@@ -93,13 +100,13 @@ bus_driver_get_conn_helper (DBusConnection  *connection,
       dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
                       "Could not get %s of name '%s': no such name",
                       what_we_want, name);
-      return NULL;
+      return BUS_DRIVER_FOUND_ERROR;
     }
 
-  if (name_p != NULL)
-    *name_p = name;
+  if (peer_conn_p != NULL)
+    *peer_conn_p = conn;
 
-  return conn;
+  return BUS_DRIVER_FOUND_PEER;
 }
 
 /*
@@ -203,6 +210,67 @@ static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
                                                     DBusError      *error);
 
 dbus_bool_t
+bus_driver_send_connection_overflow (DBusConnection *connection,
+                                     BusTransaction *transaction,
+                                     DBusError      *error)
+{
+  DBusMessage *message;
+  dbus_bool_t retval;
+  const char *name;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  message = dbus_message_new_signal (DBUS_PATH_DBUS,
+                                     DBUS_INTERFACE_TIZEN,
+                                     DBUS_TIZEN_CONNECTION_OVERFLOW_SIGNAL);
+
+  if (message == NULL)
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+    goto oom;
+
+  name = bus_connection_get_name (connection);
+
+  if (!dbus_message_append_args (message,
+                                 DBUS_TYPE_STRING, &name,
+                                 DBUS_TYPE_INVALID))
+    goto oom;
+
+  _dbus_assert (dbus_message_has_signature (message, "s"));
+
+  if (!bus_transaction_capture (transaction, NULL, NULL, message))
+    goto oom;
+
+  switch (bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error))
+    {
+    case BUS_RESULT_TRUE:
+      retval = TRUE;
+      break;
+    case BUS_RESULT_FALSE:
+      retval = FALSE;
+      break;
+    case BUS_RESULT_LATER:
+    default:
+      /* should never happen */
+      _dbus_assert_not_reached ("bus_dispatch_matches returned BUS_RESULT_LATER unexpectedly");
+      retval = FALSE;
+      break;
+    }
+  dbus_message_unref (message);
+
+  return retval;
+
+ oom:
+  dbus_message_unref (message);
+  BUS_SET_OOM (error);
+  return FALSE;
+}
+
+dbus_bool_t
 bus_driver_send_service_owner_changed (const char     *service_name,
                                       const char     *old_owner,
                                       const char     *new_owner,
@@ -243,10 +311,23 @@ bus_driver_send_service_owner_changed (const char     *service_name,
 
   _dbus_assert (dbus_message_has_signature (message, "sss"));
 
-  if (!bus_transaction_capture (transaction, NULL, message))
+  if (!bus_transaction_capture (transaction, NULL, NULL, message))
     goto oom;
 
-  retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
+  switch (bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error))
+    {
+    case BUS_RESULT_TRUE:
+      retval = TRUE;
+      break;
+    case BUS_RESULT_FALSE:
+      retval = FALSE;
+      break;
+    default:
+      /* should never happen */
+      _dbus_assert_not_reached ("bus_dispatch_matches returned BUS_RESULT_LATER unexpectedly");
+      retval = FALSE;
+      break;
+    }
   dbus_message_unref (message);
 
   return retval;
@@ -403,7 +484,7 @@ create_unique_client_name (BusRegistry *registry,
   return TRUE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_hello (DBusConnection *connection,
                          BusTransaction *transaction,
                          DBusMessage    *message,
@@ -411,9 +492,12 @@ bus_driver_handle_hello (DBusConnection *connection,
 {
   DBusString unique_name;
   BusService *service;
-  dbus_bool_t retval;
+  BusResult retval;
   BusRegistry *registry;
   BusConnections *connections;
+  DBusError tmp_error;
+  int limit;
+  const char *limit_name;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -422,7 +506,7 @@ bus_driver_handle_hello (DBusConnection *connection,
       /* We already handled an Hello message for this connection. */
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Already handled an Hello message");
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   /* Note that when these limits are exceeded we don't disconnect the
@@ -431,21 +515,29 @@ bus_driver_handle_hello (DBusConnection *connection,
    * incomplete connections. It's even OK if the connection wants to
    * retry the hello message, we support that.
    */
+  dbus_error_init (&tmp_error);
   connections = bus_connection_get_connections (connection);
   if (!bus_connections_check_limits (connections, connection,
-                                     error))
+                                     &limit_name, &limit,
+                                     &tmp_error))
     {
-      _DBUS_ASSERT_ERROR_IS_SET (error);
-      return FALSE;
+      BusContext *context;
+
+      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
+      context = bus_connection_get_context (connection);
+      bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, "%s (%s=%d)",
+          tmp_error.message, limit_name, limit);
+      dbus_move_error (&tmp_error, error);
+      return BUS_RESULT_FALSE;
     }
 
   if (!_dbus_string_init (&unique_name))
     {
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
-  retval = FALSE;
+  retval = BUS_RESULT_FALSE;
 
   registry = bus_connection_get_registry (connection);
 
@@ -478,7 +570,7 @@ bus_driver_handle_hello (DBusConnection *connection,
     goto out_0;
 
   _dbus_assert (bus_connection_is_active (connection));
-  retval = TRUE;
+  retval = BUS_RESULT_TRUE;
 
  out_0:
   _dbus_string_free (&unique_name);
@@ -530,7 +622,7 @@ bus_driver_send_welcome_message (DBusConnection *connection,
     }
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_list_services (DBusConnection *connection,
                                  BusTransaction *transaction,
                                  DBusMessage    *message,
@@ -552,14 +644,14 @@ bus_driver_handle_list_services (DBusConnection *connection,
   if (reply == NULL)
     {
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   if (!bus_registry_list_services (registry, &services, &len))
     {
       dbus_message_unref (reply);
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   dbus_message_iter_init_append (reply, &iter);
@@ -571,7 +663,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
       dbus_free_string_array (services);
       dbus_message_unref (reply);
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   {
@@ -583,7 +675,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
         dbus_free_string_array (services);
         dbus_message_unref (reply);
         BUS_SET_OOM (error);
-        return FALSE;
+        return BUS_RESULT_FALSE;
       }
   }
 
@@ -596,7 +688,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
           dbus_free_string_array (services);
           dbus_message_unref (reply);
           BUS_SET_OOM (error);
-          return FALSE;
+          return BUS_RESULT_FALSE;
         }
       ++i;
     }
@@ -607,23 +699,23 @@ bus_driver_handle_list_services (DBusConnection *connection,
     {
       dbus_message_unref (reply);
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   if (!bus_transaction_send_from_driver (transaction, connection, reply))
     {
       dbus_message_unref (reply);
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
   else
     {
       dbus_message_unref (reply);
-      return TRUE;
+      return BUS_RESULT_TRUE;
     }
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_list_activatable_services (DBusConnection *connection,
                                             BusTransaction *transaction,
                                             DBusMessage    *message,
@@ -645,14 +737,14 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
   if (reply == NULL)
     {
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   if (!bus_activation_list_services (activation, &services, &len))
     {
       dbus_message_unref (reply);
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   dbus_message_iter_init_append (reply, &iter);
@@ -664,7 +756,7 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
       dbus_free_string_array (services);
       dbus_message_unref (reply);
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   {
@@ -676,7 +768,7 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
        dbus_free_string_array (services);
        dbus_message_unref (reply);
        BUS_SET_OOM (error);
-       return FALSE;
+       return BUS_RESULT_FALSE;
       }
   }
 
@@ -689,7 +781,7 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
          dbus_free_string_array (services);
          dbus_message_unref (reply);
          BUS_SET_OOM (error);
-         return FALSE;
+         return BUS_RESULT_FALSE;
        }
       ++i;
     }
@@ -700,23 +792,23 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
     {
       dbus_message_unref (reply);
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   if (!bus_transaction_send_from_driver (transaction, connection, reply))
     {
       dbus_message_unref (reply);
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
   else
     {
       dbus_message_unref (reply);
-      return TRUE;
+      return BUS_RESULT_TRUE;
     }
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_acquire_service (DBusConnection *connection,
                                    BusTransaction *transaction,
                                    DBusMessage    *message,
@@ -727,7 +819,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
   const char *name;
   dbus_uint32_t service_reply;
   dbus_uint32_t flags;
-  dbus_bool_t retval;
+  BusResult retval;
   BusRegistry *registry;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -738,20 +830,28 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
                               DBUS_TYPE_STRING, &name,
                               DBUS_TYPE_UINT32, &flags,
                               DBUS_TYPE_INVALID))
-    return FALSE;
+    return BUS_RESULT_FALSE;
 
   _dbus_verbose ("Trying to own name %s with flags 0x%x\n", name, flags);
 
-  retval = FALSE;
+  retval = BUS_RESULT_FALSE;
   reply = NULL;
 
   _dbus_string_init_const (&service_name, name);
 
-  if (!bus_registry_acquire_service (registry, connection,
-                                     &service_name, flags,
-                                     &service_reply, transaction,
-                                     error))
-    goto out;
+  switch (bus_registry_acquire_service (registry, connection, message,
+                                       &service_name, flags,
+                                       &service_reply, transaction,
+                                       error))
+    {
+      case BUS_RESULT_TRUE:
+        break;
+      case BUS_RESULT_FALSE:
+        goto out;
+      case BUS_RESULT_LATER:
+        retval = BUS_RESULT_LATER;
+        goto out;
+    }
 
   reply = dbus_message_new_method_return (message);
   if (reply == NULL)
@@ -772,7 +872,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
       goto out;
     }
 
-  retval = TRUE;
+  retval = BUS_RESULT_TRUE;
 
  out:
   if (reply)
@@ -780,7 +880,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
   return retval;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_release_service (DBusConnection *connection,
                                    BusTransaction *transaction,
                                    DBusMessage    *message,
@@ -790,7 +890,7 @@ bus_driver_handle_release_service (DBusConnection *connection,
   DBusString service_name;
   const char *name;
   dbus_uint32_t service_reply;
-  dbus_bool_t retval;
+  BusResult retval;
   BusRegistry *registry;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -800,11 +900,11 @@ bus_driver_handle_release_service (DBusConnection *connection,
   if (!dbus_message_get_args (message, error,
                               DBUS_TYPE_STRING, &name,
                               DBUS_TYPE_INVALID))
-    return FALSE;
+    return BUS_RESULT_FALSE;
 
   _dbus_verbose ("Trying to release name %s\n", name);
 
-  retval = FALSE;
+  retval = BUS_RESULT_FALSE;
   reply = NULL;
 
   _dbus_string_init_const (&service_name, name);
@@ -833,7 +933,7 @@ bus_driver_handle_release_service (DBusConnection *connection,
       goto out;
     }
 
-  retval = TRUE;
+  retval = BUS_RESULT_TRUE;
 
  out:
   if (reply)
@@ -841,7 +941,7 @@ bus_driver_handle_release_service (DBusConnection *connection,
   return retval;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_service_exists (DBusConnection *connection,
                                   BusTransaction *transaction,
                                   DBusMessage    *message,
@@ -852,7 +952,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
   BusService *service;
   dbus_bool_t service_exists;
   const char *name;
-  dbus_bool_t retval;
+  BusResult retval;
   BusRegistry *registry;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -862,9 +962,9 @@ bus_driver_handle_service_exists (DBusConnection *connection,
   if (!dbus_message_get_args (message, error,
                               DBUS_TYPE_STRING, &name,
                               DBUS_TYPE_INVALID))
-    return FALSE;
+    return BUS_RESULT_FALSE;
 
-  retval = FALSE;
+  retval = BUS_RESULT_FALSE;
 
   if (strcmp (name, DBUS_SERVICE_DBUS) == 0)
     {
@@ -898,7 +998,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
       goto out;
     }
 
-  retval = TRUE;
+  retval = BUS_RESULT_TRUE;
 
  out:
   if (reply)
@@ -907,7 +1007,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
   return retval;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_activate_service (DBusConnection *connection,
                                     BusTransaction *transaction,
                                     DBusMessage    *message,
@@ -915,7 +1015,7 @@ bus_driver_handle_activate_service (DBusConnection *connection,
 {
   dbus_uint32_t flags;
   const char *name;
-  dbus_bool_t retval;
+  BusResult retval;
   BusActivation *activation;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -929,30 +1029,30 @@ bus_driver_handle_activate_service (DBusConnection *connection,
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
       _dbus_verbose ("No memory to get arguments to StartServiceByName\n");
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
-  retval = FALSE;
+  retval = BUS_RESULT_FALSE;
 
-  if (!bus_activation_activate_service (activation, connection, transaction, FALSE,
-                                        message, name, error))
+  if (bus_activation_activate_service (activation, connection, transaction, FALSE,
+                                        message, name, error, NULL) == BUS_RESULT_FALSE)
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
       _dbus_verbose ("bus_activation_activate_service() failed\n");
       goto out;
     }
 
-  retval = TRUE;
+  retval = BUS_RESULT_TRUE;
 
  out:
   return retval;
 }
 
-static dbus_bool_t
-send_ack_reply (DBusConnection *connection,
-                BusTransaction *transaction,
-                DBusMessage    *message,
-                DBusError      *error)
+dbus_bool_t
+bus_driver_send_ack_reply (DBusConnection *connection,
+                           BusTransaction *transaction,
+                           DBusMessage    *message,
+                           DBusError      *error)
 {
   DBusMessage *reply;
 
@@ -978,14 +1078,81 @@ send_ack_reply (DBusConnection *connection,
   return TRUE;
 }
 
+/*
+ * Send a message from the driver, activating the destination if necessary.
+ * The message must already have a destination set.
+ */
 static dbus_bool_t
+bus_driver_send_or_activate (BusTransaction *transaction,
+                             DBusMessage    *message,
+                             DBusError      *error)
+{
+  BusContext *context;
+  BusService *service;
+  const char *service_name;
+  DBusString service_string;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  service_name = dbus_message_get_destination (message);
+
+  _dbus_assert (service_name != NULL);
+
+  _dbus_string_init_const (&service_string, service_name);
+
+  context = bus_transaction_get_context (transaction);
+
+  service = bus_registry_lookup (bus_context_get_registry (context),
+                                 &service_string);
+
+  if (service == NULL)
+    {
+      /* destination isn't connected yet; pass the message to activation */
+      BusActivation *activation;
+
+      activation = bus_context_get_activation (context);
+
+      if (!bus_transaction_capture (transaction, NULL, NULL, message))
+        {
+          BUS_SET_OOM (error);
+          _dbus_verbose ("No memory for bus_transaction_capture()");
+          return FALSE;
+        }
+
+      if (bus_activation_activate_service (activation, NULL, transaction, TRUE,
+                                            message, service_name, error, NULL) == BUS_RESULT_FALSE)
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          _dbus_verbose ("bus_activation_activate_service() failed");
+          return FALSE;
+        }
+    }
+  else
+    {
+      DBusConnection *service_conn;
+
+      service_conn = bus_service_get_primary_owners_connection (service);
+
+      if (!bus_transaction_send_from_driver (transaction, service_conn, message))
+        {
+          BUS_SET_OOM (error);
+          _dbus_verbose ("No memory for bus_transaction_send_from_driver()");
+          return FALSE;
+        }
+    }
+
+  return TRUE;
+}
+
+static BusResult
 bus_driver_handle_update_activation_environment (DBusConnection *connection,
                                                  BusTransaction *transaction,
                                                  DBusMessage    *message,
                                                  DBusError      *error)
 {
-  dbus_bool_t retval;
+  BusResult retval;
   BusActivation *activation;
+  BusContext *context;
   DBusMessageIter iter;
   DBusMessageIter dict_iter;
   DBusMessageIter dict_entry_iter;
@@ -993,23 +1160,20 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
   int key_type;
   DBusList *keys, *key_link;
   DBusList *values, *value_link;
+  DBusMessage *systemd_message;
+  DBusMessageIter systemd_iter;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
-  if (!bus_driver_check_message_is_for_us (message, error))
-    return FALSE;
+  context = bus_connection_get_context (connection);
 
-#ifdef DBUS_UNIX
+  if (bus_context_get_servicehelper (context) != NULL)
     {
-      /* UpdateActivationEnvironment is basically a recipe for privilege
-       * escalation so let's be extra-careful: do not allow the sysadmin
-       * to shoot themselves in the foot.
-       */
-      if (!bus_driver_check_caller_is_privileged (connection, transaction,
-                                                  message, error))
-        return FALSE;
+      dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+                      "Cannot change activation environment "
+                      "on a system bus.");
+      return BUS_RESULT_FALSE;
     }
-#endif
 
   activation = bus_connection_get_activation (connection);
 
@@ -1022,7 +1186,8 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
 
   dbus_message_iter_recurse (&iter, &dict_iter);
 
-  retval = FALSE;
+  retval = BUS_RESULT_FALSE;
+  systemd_message = NULL;
 
   /* Then loop through the sent dictionary, add the location of
    * the environment keys and values to lists. The result will
@@ -1077,6 +1242,33 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
 
   _dbus_assert (_dbus_list_get_length (&keys) == _dbus_list_get_length (&values));
 
+  if (bus_context_get_systemd_activation (bus_connection_get_context (connection)))
+    {
+      /* Prepare a call to forward environment updates to systemd */
+      systemd_message = dbus_message_new_method_call ("org.freedesktop.systemd1",
+                                                      "/org/freedesktop/systemd1",
+                                                      "org.freedesktop.systemd1.Manager",
+                                                      "SetEnvironment");
+      if (systemd_message == NULL ||
+          !dbus_message_set_sender (systemd_message, DBUS_SERVICE_DBUS))
+        {
+          BUS_SET_OOM (error);
+          _dbus_verbose ("No memory to create systemd message\n");
+          goto out;
+        }
+
+      dbus_message_set_no_reply (systemd_message, TRUE);
+      dbus_message_iter_init_append (systemd_message, &iter);
+
+      if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
+                                             &systemd_iter))
+        {
+          BUS_SET_OOM (error);
+          _dbus_verbose ("No memory to open systemd message container\n");
+          goto out;
+        }
+    }
+
   key_link = keys;
   value_link = values;
   while (key_link != NULL)
@@ -1089,11 +1281,41 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
 
       if (!bus_activation_set_environment_variable (activation,
                                                     key, value, error))
-      {
+        {
           _DBUS_ASSERT_ERROR_IS_SET (error);
           _dbus_verbose ("bus_activation_set_environment_variable() failed\n");
           break;
-      }
+        }
+
+      if (systemd_message != NULL)
+        {
+          DBusString envline;
+          const char *s;
+
+          /* SetEnvironment wants an array of KEY=VALUE strings */
+          if (!_dbus_string_init (&envline) ||
+              !_dbus_string_append_printf (&envline, "%s=%s", key, value))
+            {
+              BUS_SET_OOM (error);
+              _dbus_verbose ("No memory to format systemd environment line\n");
+              _dbus_string_free (&envline);
+              break;
+            }
+
+          s = _dbus_string_get_data (&envline);
+
+          if (!dbus_message_iter_append_basic (&systemd_iter,
+                                               DBUS_TYPE_STRING, &s))
+            {
+              BUS_SET_OOM (error);
+              _dbus_verbose ("No memory to append systemd environment line\n");
+              _dbus_string_free (&envline);
+              break;
+            }
+
+          _dbus_string_free (&envline);
+        }
+
       key_link = _dbus_list_get_next_link (&keys, key_link);
       value_link = _dbus_list_get_next_link (&values, value_link);
   }
@@ -1103,21 +1325,43 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
    * matter, so we're punting for now.
    */
   if (key_link != NULL)
-    goto out;
+    {
+      if (systemd_message != NULL)
+        dbus_message_iter_abandon_container (&iter, &systemd_iter);
+      goto out;
+    }
+
+  if (systemd_message != NULL)
+    {
+      if (!dbus_message_iter_close_container (&iter, &systemd_iter))
+        {
+          BUS_SET_OOM (error);
+          _dbus_verbose ("No memory to close systemd message container\n");
+          goto out;
+        }
 
-  if (!send_ack_reply (connection, transaction,
-                       message, error))
+      if (!bus_driver_send_or_activate (transaction, systemd_message, error))
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          _dbus_verbose ("bus_driver_send_or_activate() failed\n");
+          goto out;
+        }
+    }
+
+  if (!bus_driver_send_ack_reply (connection, transaction, message, error))
     goto out;
 
-  retval = TRUE;
+  retval = BUS_RESULT_TRUE;
 
  out:
+  if (systemd_message != NULL)
+    dbus_message_unref (systemd_message);
   _dbus_list_clear (&keys);
   _dbus_list_clear (&values);
   return retval;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_add_match (DBusConnection *connection,
                              BusTransaction *transaction,
                              DBusMessage    *message,
@@ -1127,6 +1371,7 @@ bus_driver_handle_add_match (DBusConnection *connection,
   const char *text, *bustype;
   DBusString str;
   BusMatchmaker *matchmaker;
+  int limit;
   BusContext *context;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -1134,15 +1379,25 @@ bus_driver_handle_add_match (DBusConnection *connection,
   text = NULL;
   rule = NULL;
 
-  if (bus_connection_get_n_match_rules (connection) >=
-      bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction)))
+  context = bus_transaction_get_context (transaction);
+  limit = bus_context_get_max_match_rules_per_connection (context);
+
+  if (bus_connection_get_n_match_rules (connection) >= limit)
     {
-      dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
+      DBusError tmp_error;
+
+      dbus_error_init (&tmp_error);
+      dbus_set_error (&tmp_error, DBUS_ERROR_LIMITS_EXCEEDED,
                       "Connection \"%s\" is not allowed to add more match rules "
-                      "(increase limits in configuration file if required)",
+                      "(increase limits in configuration file if required; "
+                      "max_match_rules_per_connection=%d)",
                       bus_connection_is_active (connection) ?
                       bus_connection_get_name (connection) :
-                      "(inactive)");
+                      "(inactive)",
+                      limit);
+      bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, "%s",
+                       tmp_error.message);
+      dbus_move_error (&tmp_error, error);
       goto failed;
     }
 
@@ -1160,11 +1415,17 @@ bus_driver_handle_add_match (DBusConnection *connection,
   if (rule == NULL)
     goto failed;
 
-  context = bus_transaction_get_context (transaction);
-  bustype = context ? bus_context_get_type (context) : NULL;
-  if (bus_match_rule_get_client_is_eavesdropping (rule) &&
-      !bus_apparmor_allows_eavesdropping (connection, bustype, error))
-    goto failed;
+  bustype = bus_context_get_type (context);
+
+  if (bus_match_rule_get_client_is_eavesdropping (rule))
+    {
+      if (!bus_driver_check_caller_is_privileged (connection,
+                                                  transaction,
+                                                  message,
+                                                  error) ||
+          !bus_apparmor_allows_eavesdropping (connection, bustype, error))
+        goto failed;
+    }
 
   matchmaker = bus_connection_get_matchmaker (connection);
 
@@ -1174,8 +1435,7 @@ bus_driver_handle_add_match (DBusConnection *connection,
       goto failed;
     }
 
-  if (!send_ack_reply (connection, transaction,
-                       message, error))
+  if (!bus_driver_send_ack_reply (connection, transaction, message, error))
     {
       bus_matchmaker_remove_rule (matchmaker, rule);
       goto failed;
@@ -1183,16 +1443,16 @@ bus_driver_handle_add_match (DBusConnection *connection,
 
   bus_match_rule_unref (rule);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  failed:
   _DBUS_ASSERT_ERROR_IS_SET (error);
   if (rule)
     bus_match_rule_unref (rule);
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_remove_match (DBusConnection *connection,
                                 BusTransaction *transaction,
                                 DBusMessage    *message,
@@ -1225,8 +1485,7 @@ bus_driver_handle_remove_match (DBusConnection *connection,
   /* Send the ack before we remove the rule, since the ack is undone
    * on transaction cancel, but rule removal isn't.
    */
-  if (!send_ack_reply (connection, transaction,
-                       message, error))
+  if (!bus_driver_send_ack_reply (connection, transaction, message, error))
     goto failed;
 
   matchmaker = bus_connection_get_matchmaker (connection);
@@ -1236,16 +1495,16 @@ bus_driver_handle_remove_match (DBusConnection *connection,
 
   bus_match_rule_unref (rule);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  failed:
   _DBUS_ASSERT_ERROR_IS_SET (error);
   if (rule)
     bus_match_rule_unref (rule);
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_get_service_owner (DBusConnection *connection,
                                     BusTransaction *transaction,
                                     DBusMessage    *message,
@@ -1315,7 +1574,7 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
 
   dbus_message_unref (reply);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   BUS_SET_OOM (error);
@@ -1324,15 +1583,17 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
   _DBUS_ASSERT_ERROR_IS_SET (error);
   if (reply)
     dbus_message_unref (reply);
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_list_queued_owners (DBusConnection *connection,
                                      BusTransaction *transaction,
                                      DBusMessage    *message,
                                      DBusError      *error)
 {
+  static const char dbus_service_name[] = DBUS_SERVICE_DBUS;
+
   const char *text;
   DBusList *base_names;
   DBusList *link;
@@ -1341,7 +1602,6 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
   BusService *service;
   DBusMessage *reply;
   DBusMessageIter iter, array_iter;
-  char *dbus_service_name = DBUS_SERVICE_DBUS;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -1362,7 +1622,7 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
       _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS))
     {
       /* ORG_FREEDESKTOP_DBUS owns itself */
-      if (! _dbus_list_append (&base_names, dbus_service_name))
+      if (! _dbus_list_append (&base_names, (char *) dbus_service_name))
         goto oom;
     }
   else if (service == NULL)
@@ -1418,7 +1678,7 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
 
   dbus_message_unref (reply);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   BUS_SET_OOM (error);
@@ -1431,10 +1691,10 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
   if (base_names)
     _dbus_list_clear (&base_names);
 
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
                                             BusTransaction *transaction,
                                             DBusMessage    *message,
@@ -1442,25 +1702,33 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
 {
   DBusConnection *conn;
   DBusMessage *reply;
-  unsigned long uid;
+  dbus_uid_t uid;
   dbus_uint32_t uid32;
   const char *service;
+  BusDriverFound found;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   reply = NULL;
 
-  conn = bus_driver_get_conn_helper (connection, message, "UID", &service,
-                                     error);
-
-  if (conn == NULL)
-    goto failed;
-
-  reply = dbus_message_new_method_return (message);
-  if (reply == NULL)
-    goto oom;
+  found = bus_driver_get_conn_helper (connection, message, "UID", &service,
+                                      &conn, error);
+  switch (found)
+    {
+      case BUS_DRIVER_FOUND_SELF:
+        uid = _dbus_getuid ();
+        break;
+      case BUS_DRIVER_FOUND_PEER:
+        if (!dbus_connection_get_unix_user (conn, &uid))
+          uid = DBUS_UID_UNSET;
+        break;
+      case BUS_DRIVER_FOUND_ERROR:
+        /* fall through */
+      default:
+        goto failed;
+    }
 
-  if (!dbus_connection_get_unix_user (conn, &uid))
+  if (uid == DBUS_UID_UNSET)
     {
       dbus_set_error (error,
                       DBUS_ERROR_FAILED,
@@ -1468,6 +1736,10 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
       goto failed;
     }
 
+  reply = dbus_message_new_method_return (message);
+  if (reply == NULL)
+    goto oom;
+
   uid32 = uid;
   if (! dbus_message_append_args (reply,
                                   DBUS_TYPE_UINT32, &uid32,
@@ -1479,7 +1751,7 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
 
   dbus_message_unref (reply);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   BUS_SET_OOM (error);
@@ -1488,10 +1760,10 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
   _DBUS_ASSERT_ERROR_IS_SET (error);
   if (reply)
     dbus_message_unref (reply);
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
                                                  BusTransaction *transaction,
                                                  DBusMessage    *message,
@@ -1499,25 +1771,33 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
 {
   DBusConnection *conn;
   DBusMessage *reply;
-  unsigned long pid;
+  dbus_pid_t pid;
   dbus_uint32_t pid32;
   const char *service;
+  BusDriverFound found;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   reply = NULL;
 
-  conn = bus_driver_get_conn_helper (connection, message, "PID", &service,
-                                     error);
-
-  if (conn == NULL)
-    goto failed;
-
-  reply = dbus_message_new_method_return (message);
-  if (reply == NULL)
-    goto oom;
+  found = bus_driver_get_conn_helper (connection, message, "PID", &service,
+                                      &conn, error);
+  switch (found)
+    {
+      case BUS_DRIVER_FOUND_SELF:
+        pid = _dbus_getpid ();
+        break;
+      case BUS_DRIVER_FOUND_PEER:
+        if (!dbus_connection_get_unix_process_id (conn, &pid))
+          pid = DBUS_PID_UNSET;
+        break;
+      case BUS_DRIVER_FOUND_ERROR:
+        /* fall through */
+      default:
+        goto failed;
+    }
 
-  if (!dbus_connection_get_unix_process_id (conn, &pid))
+  if (pid == DBUS_PID_UNSET)
     {
       dbus_set_error (error,
                       DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,
@@ -1525,8 +1805,12 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
       goto failed;
     }
 
-  pid32 = pid;
-  if (! dbus_message_append_args (reply,
+  reply = dbus_message_new_method_return (message);
+  if (reply == NULL)
+    goto oom;
+
+  pid32 = pid;
+  if (! dbus_message_append_args (reply,
                                   DBUS_TYPE_UINT32, &pid32,
                                   DBUS_TYPE_INVALID))
     goto oom;
@@ -1536,7 +1820,7 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
 
   dbus_message_unref (reply);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   BUS_SET_OOM (error);
@@ -1545,10 +1829,10 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
   _DBUS_ASSERT_ERROR_IS_SET (error);
   if (reply)
     dbus_message_unref (reply);
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
                                              BusTransaction *transaction,
                                              DBusMessage    *message,
@@ -1557,24 +1841,31 @@ bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
   DBusConnection *conn;
   DBusMessage *reply;
   void *data = NULL;
-  dbus_uint32_t data_size;
+  dbus_int32_t data_size;
   const char *service;
+  BusDriverFound found;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   reply = NULL;
 
-  conn = bus_driver_get_conn_helper (connection, message,
-                                     "audit session data", &service, error);
+  found = bus_driver_get_conn_helper (connection, message, "audit session data",
+                                      &service, &conn, error);
 
-  if (conn == NULL)
+  if (found == BUS_DRIVER_FOUND_ERROR)
     goto failed;
 
   reply = dbus_message_new_method_return (message);
   if (reply == NULL)
     goto oom;
 
-  if (!dbus_connection_get_adt_audit_session_data (conn, &data, &data_size) || data == NULL)
+  /* We don't know how to find "ADT audit session data" for the bus daemon
+   * itself. Is that even meaningful?
+   * FIXME: Implement this or briefly note it makes no sense.
+   */
+  if (found != BUS_DRIVER_FOUND_PEER ||
+      !dbus_connection_get_adt_audit_session_data (conn, &data, &data_size) ||
+      data == NULL)
     {
       dbus_set_error (error,
                       DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN,
@@ -1592,7 +1883,7 @@ bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
 
   dbus_message_unref (reply);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   BUS_SET_OOM (error);
@@ -1601,10 +1892,10 @@ bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
   _DBUS_ASSERT_ERROR_IS_SET (error);
   if (reply)
     dbus_message_unref (reply);
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_get_connection_selinux_security_context (DBusConnection *connection,
                                                           BusTransaction *transaction,
                                                           DBusMessage    *message,
@@ -1614,22 +1905,29 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne
   DBusMessage *reply;
   BusSELinuxID *context;
   const char *service;
+  BusDriverFound found;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   reply = NULL;
 
-  conn = bus_driver_get_conn_helper (connection, message, "security context",
-                                     &service, error);
+  found = bus_driver_get_conn_helper (connection, message, "security context",
+                                      &service, &conn, error);
 
-  if (conn == NULL)
+  if (found == BUS_DRIVER_FOUND_ERROR)
     goto failed;
 
   reply = dbus_message_new_method_return (message);
   if (reply == NULL)
     goto oom;
 
-  context = bus_connection_get_selinux_id (conn);
+  if (found == BUS_DRIVER_FOUND_SELF)
+    context = bus_selinux_get_self ();
+  else if (found == BUS_DRIVER_FOUND_PEER)
+    context = bus_connection_get_selinux_id (conn);
+  else
+    context = NULL;
+
   if (!context)
     {
       dbus_set_error (error,
@@ -1646,7 +1944,7 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne
 
   dbus_message_unref (reply);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   BUS_SET_OOM (error);
@@ -1655,10 +1953,10 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne
   _DBUS_ASSERT_ERROR_IS_SET (error);
   if (reply)
     dbus_message_unref (reply);
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_get_connection_credentials (DBusConnection *connection,
                                               BusTransaction *transaction,
                                               DBusMessage    *message,
@@ -1668,19 +1966,36 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
   DBusMessage *reply;
   DBusMessageIter reply_iter;
   DBusMessageIter array_iter;
-  unsigned long ulong_val;
+  unsigned long ulong_uid, ulong_pid;
   char *s;
   const char *service;
+  BusDriverFound found;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   reply = NULL;
 
-  conn = bus_driver_get_conn_helper (connection, message, "credentials",
-                                     &service, error);
+  found = bus_driver_get_conn_helper (connection, message, "credentials",
+                                      &service, &conn, error);
 
-  if (conn == NULL)
-    goto failed;
+  switch (found)
+    {
+      case BUS_DRIVER_FOUND_SELF:
+        ulong_pid = _dbus_getpid ();
+        ulong_uid = _dbus_getuid ();
+        break;
+
+      case BUS_DRIVER_FOUND_PEER:
+        if (!dbus_connection_get_unix_process_id (conn, &ulong_pid))
+          ulong_pid = DBUS_PID_UNSET;
+        if (!dbus_connection_get_unix_user (conn, &ulong_uid))
+          ulong_uid = DBUS_UID_UNSET;
+        break;
+      case BUS_DRIVER_FOUND_ERROR:
+        /* fall through */
+      default:
+        goto failed;
+    }
 
   reply = _dbus_asv_new_method_return (message, &reply_iter, &array_iter);
   if (reply == NULL)
@@ -1688,23 +2003,19 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
 
   /* we can't represent > 32-bit pids; if your system needs them, please
    * add ProcessID64 to the spec or something */
-  if (dbus_connection_get_unix_process_id (conn, &ulong_val) &&
-      ulong_val <= _DBUS_UINT32_MAX)
-    {
-      if (!_dbus_asv_add_uint32 (&array_iter, "ProcessID", ulong_val))
-        goto oom;
-    }
+  if (ulong_pid <= _DBUS_UINT32_MAX && ulong_pid != DBUS_PID_UNSET &&
+      !_dbus_asv_add_uint32 (&array_iter, "ProcessID", ulong_pid))
+    goto oom;
 
   /* we can't represent > 32-bit uids; if your system needs them, please
    * add UnixUserID64 to the spec or something */
-  if (dbus_connection_get_unix_user (conn, &ulong_val) &&
-      ulong_val <= _DBUS_UINT32_MAX)
-    {
-      if (!_dbus_asv_add_uint32 (&array_iter, "UnixUserID", ulong_val))
-        goto oom;
-    }
+  if (ulong_uid <= _DBUS_UINT32_MAX && ulong_uid != DBUS_UID_UNSET &&
+      !_dbus_asv_add_uint32 (&array_iter, "UnixUserID", ulong_uid))
+    goto oom;
 
-  if (dbus_connection_get_windows_user (conn, &s))
+  /* FIXME: Obtain the Windows user of the bus daemon itself */
+  if (found == BUS_DRIVER_FOUND_PEER &&
+      dbus_connection_get_windows_user (conn, &s))
     {
       DBusString str;
       dbus_bool_t result;
@@ -1726,7 +2037,9 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
       dbus_free (s);
     }
 
-  if (_dbus_connection_get_linux_security_label (conn, &s))
+  /* FIXME: Obtain the security label for the bus daemon itself */
+  if (found == BUS_DRIVER_FOUND_PEER &&
+      _dbus_connection_get_linux_security_label (conn, &s))
     {
       if (s == NULL)
         goto oom;
@@ -1757,7 +2070,7 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
 
   dbus_message_unref (reply);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   BUS_SET_OOM (error);
@@ -1771,10 +2084,10 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
       dbus_message_unref (reply);
     }
 
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_reload_config (DBusConnection *connection,
                                 BusTransaction *transaction,
                                 DBusMessage    *message,
@@ -1799,7 +2112,7 @@ bus_driver_handle_reload_config (DBusConnection *connection,
     goto oom;
 
   dbus_message_unref (reply);
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   BUS_SET_OOM (error);
@@ -1808,7 +2121,7 @@ bus_driver_handle_reload_config (DBusConnection *connection,
   _DBUS_ASSERT_ERROR_IS_SET (error);
   if (reply)
     dbus_message_unref (reply);
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
 #ifdef DBUS_ENABLE_VERBOSE_MODE
@@ -1877,7 +2190,7 @@ bus_driver_handle_disable_verbose (DBusConnection *connection,
 }
 #endif
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_get_id (DBusConnection *connection,
                           BusTransaction *transaction,
                           DBusMessage    *message,
@@ -1893,7 +2206,7 @@ bus_driver_handle_get_id (DBusConnection *connection,
   if (!_dbus_string_init (&uuid))
     {
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   reply = NULL;
@@ -1919,7 +2232,7 @@ bus_driver_handle_get_id (DBusConnection *connection,
 
   _dbus_string_free (&uuid);
   dbus_message_unref (reply);
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -1929,7 +2242,7 @@ bus_driver_handle_get_id (DBusConnection *connection,
   if (reply)
     dbus_message_unref (reply);
   _dbus_string_free (&uuid);
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
 static dbus_bool_t
@@ -1952,18 +2265,11 @@ bus_driver_handle_become_monitor (DBusConnection *connection,
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
-  if (!bus_driver_check_message_is_for_us (message, error))
-    goto out;
-
   context = bus_transaction_get_context (transaction);
   bustype = context ? bus_context_get_type (context) : NULL;
   if (!bus_apparmor_allows_eavesdropping (connection, bustype, error))
     goto out;
 
-  if (!bus_driver_check_caller_is_privileged (connection, transaction,
-                                              message, error))
-    goto out;
-
   if (!dbus_message_get_args (message, error,
         DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &match_rules, &n_match_rules,
         DBUS_TYPE_UINT32, &flags,
@@ -2006,10 +2312,7 @@ bus_driver_handle_become_monitor (DBusConnection *connection,
       rule = bus_match_rule_parse (connection, &str, error);
 
       if (rule == NULL)
-        {
-          BUS_SET_OOM (error);
-          goto out;
-        }
+        goto out;
 
       /* monitors always eavesdrop */
       bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
@@ -2025,7 +2328,7 @@ bus_driver_handle_become_monitor (DBusConnection *connection,
   /* Send the ack before we remove the rule, since the ack is undone
    * on transaction cancel, but becoming a monitor isn't.
    */
-  if (!send_ack_reply (connection, transaction, message, error))
+  if (!bus_driver_send_ack_reply (connection, transaction, message, error))
     goto out;
 
   if (!bus_connection_be_monitor (connection, transaction, &rules, error))
@@ -2050,17 +2353,129 @@ out:
   return ret;
 }
 
+static dbus_bool_t
+bus_driver_handle_get_machine_id (DBusConnection *connection,
+                                  BusTransaction *transaction,
+                                  DBusMessage *message,
+                                  DBusError *error)
+{
+  DBusMessage *reply = NULL;
+  DBusString uuid;
+  const char *str;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  if (!_dbus_string_init (&uuid))
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  if (!_dbus_get_local_machine_uuid_encoded (&uuid, error))
+    goto fail;
+
+  reply = dbus_message_new_method_return (message);
+
+  if (reply == NULL)
+    goto oom;
+
+  str = _dbus_string_get_const_data (&uuid);
+
+  if (!dbus_message_append_args (reply,
+                                 DBUS_TYPE_STRING, &str,
+                                 DBUS_TYPE_INVALID))
+    goto oom;
+
+  _dbus_assert (dbus_message_has_signature (reply, "s"));
+
+  if (!bus_transaction_send_from_driver (transaction, connection, reply))
+    goto oom;
+
+  _dbus_string_free (&uuid);
+  dbus_message_unref (reply);
+  return TRUE;
+
+oom:
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  BUS_SET_OOM (error);
+
+fail:
+  _DBUS_ASSERT_ERROR_IS_SET (error);
+
+  if (reply != NULL)
+    dbus_message_unref (reply);
+
+  _dbus_string_free (&uuid);
+  return FALSE;
+}
+
+static dbus_bool_t
+bus_driver_handle_ping (DBusConnection *connection,
+                        BusTransaction *transaction,
+                        DBusMessage *message,
+                        DBusError *error)
+{
+  return bus_driver_send_ack_reply (connection, transaction, message, error);
+}
+
+static dbus_bool_t bus_driver_handle_get (DBusConnection *connection,
+                                          BusTransaction *transaction,
+                                          DBusMessage *message,
+                                          DBusError *error);
+
+static dbus_bool_t bus_driver_handle_get_all (DBusConnection *connection,
+                                              BusTransaction *transaction,
+                                              DBusMessage *message,
+                                              DBusError *error);
+
+static dbus_bool_t bus_driver_handle_set (DBusConnection *connection,
+                                          BusTransaction *transaction,
+                                          DBusMessage *message,
+                                          DBusError *error);
+
+static dbus_bool_t features_getter (BusContext      *context,
+                                    DBusMessageIter *variant_iter);
+static dbus_bool_t interfaces_getter (BusContext      *context,
+                                      DBusMessageIter *variant_iter);
+
+typedef enum
+{
+  /* Various older methods were available at every object path. We have to
+   * preserve that behaviour for backwards compatibility, but we can at least
+   * stop doing that for newly added methods.
+   * The special Peer interface should also work at any object path.
+   * <https://bugs.freedesktop.org/show_bug.cgi?id=101256> */
+  METHOD_FLAG_ANY_PATH = (1 << 0),
+
+  /* If set, callers must be privileged. On Unix, the uid of the connection
+   * must either be the uid of this process, or 0 (root). On Windows,
+   * the SID of the connection must be the SID of this process. */
+  METHOD_FLAG_PRIVILEGED = (1 << 1),
+
+  METHOD_FLAG_NONE = 0
+} MethodFlags;
+
 typedef struct
 {
   const char *name;
   const char *in_args;
   const char *out_args;
-  dbus_bool_t (* handler) (DBusConnection *connection,
-                           BusTransaction *transaction,
-                           DBusMessage    *message,
-                           DBusError      *error);
+  BusResult (* handler) (DBusConnection *connection,
+                         BusTransaction *transaction,
+                         DBusMessage    *message,
+                         DBusError      *error);
+  MethodFlags flags;
 } MessageHandler;
 
+typedef struct
+{
+  const char *name;
+  const char *type;
+  dbus_bool_t (* getter) (BusContext      *context,
+                          DBusMessageIter *variant_iter);
+} PropertyHandler;
+
 /* For speed it might be useful to sort this in order of
  * frequency of use (but doesn't matter with only a few items
  * anyhow)
@@ -2069,114 +2484,178 @@ static const MessageHandler dbus_message_handlers[] = {
   { "Hello",
     "",
     DBUS_TYPE_STRING_AS_STRING,
-    bus_driver_handle_hello },
+    bus_driver_handle_hello,
+    METHOD_FLAG_ANY_PATH },
   { "RequestName",
     DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
     DBUS_TYPE_UINT32_AS_STRING,
-    bus_driver_handle_acquire_service },
+    bus_driver_handle_acquire_service,
+    METHOD_FLAG_ANY_PATH },
   { "ReleaseName",
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_UINT32_AS_STRING,
-    bus_driver_handle_release_service },
+    bus_driver_handle_release_service,
+    METHOD_FLAG_ANY_PATH },
   { "StartServiceByName",
     DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
     DBUS_TYPE_UINT32_AS_STRING,
-    bus_driver_handle_activate_service },
+    bus_driver_handle_activate_service,
+    METHOD_FLAG_ANY_PATH },
   { "UpdateActivationEnvironment",
     DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
     "",
-    bus_driver_handle_update_activation_environment },
+    bus_driver_handle_update_activation_environment,
+    METHOD_FLAG_PRIVILEGED },
   { "NameHasOwner",
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_BOOLEAN_AS_STRING,
-    bus_driver_handle_service_exists },
+    bus_driver_handle_service_exists,
+    METHOD_FLAG_ANY_PATH },
   { "ListNames",
     "",
     DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
-    bus_driver_handle_list_services },
+    bus_driver_handle_list_services,
+    METHOD_FLAG_ANY_PATH },
   { "ListActivatableNames",
     "",
     DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
-    bus_driver_handle_list_activatable_services },
+    bus_driver_handle_list_activatable_services,
+    METHOD_FLAG_ANY_PATH },
   { "AddMatch",
     DBUS_TYPE_STRING_AS_STRING,
     "",
-    bus_driver_handle_add_match },
+    bus_driver_handle_add_match,
+    METHOD_FLAG_ANY_PATH },
   { "RemoveMatch",
     DBUS_TYPE_STRING_AS_STRING,
     "",
-    bus_driver_handle_remove_match },
+    bus_driver_handle_remove_match,
+    METHOD_FLAG_ANY_PATH },
   { "GetNameOwner",
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_STRING_AS_STRING,
-    bus_driver_handle_get_service_owner },
+    bus_driver_handle_get_service_owner,
+    METHOD_FLAG_ANY_PATH },
   { "ListQueuedOwners",
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
-    bus_driver_handle_list_queued_owners },
+    bus_driver_handle_list_queued_owners,
+    METHOD_FLAG_ANY_PATH },
   { "GetConnectionUnixUser",
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_UINT32_AS_STRING,
-    bus_driver_handle_get_connection_unix_user },
+    bus_driver_handle_get_connection_unix_user,
+    METHOD_FLAG_ANY_PATH },
   { "GetConnectionUnixProcessID",
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_UINT32_AS_STRING,
-    bus_driver_handle_get_connection_unix_process_id },
+    bus_driver_handle_get_connection_unix_process_id,
+    METHOD_FLAG_ANY_PATH },
   { "GetAdtAuditSessionData",
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
-    bus_driver_handle_get_adt_audit_session_data },
+    bus_driver_handle_get_adt_audit_session_data,
+    METHOD_FLAG_ANY_PATH },
   { "GetConnectionSELinuxSecurityContext",
     DBUS_TYPE_STRING_AS_STRING,
     DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
-    bus_driver_handle_get_connection_selinux_security_context },
+    bus_driver_handle_get_connection_selinux_security_context,
+    METHOD_FLAG_ANY_PATH },
   { "ReloadConfig",
     "",
     "",
-    bus_driver_handle_reload_config },
+    bus_driver_handle_reload_config,
+    METHOD_FLAG_ANY_PATH },
   { "GetId",
     "",
     DBUS_TYPE_STRING_AS_STRING,
-    bus_driver_handle_get_id },
+    bus_driver_handle_get_id,
+    METHOD_FLAG_ANY_PATH },
   { "GetConnectionCredentials", "s", "a{sv}",
-    bus_driver_handle_get_connection_credentials },
+    bus_driver_handle_get_connection_credentials,
+    METHOD_FLAG_ANY_PATH },
   { NULL, NULL, NULL, NULL }
 };
 
-static dbus_bool_t bus_driver_handle_introspect (DBusConnection *,
+static const PropertyHandler dbus_property_handlers[] = {
+  { "Features", "as", features_getter },
+  { "Interfaces", "as", interfaces_getter },
+  { NULL, NULL, NULL }
+};
+
+static BusResult bus_driver_handle_introspect (DBusConnection *,
     BusTransaction *, DBusMessage *, DBusError *);
 
+static const MessageHandler properties_message_handlers[] = {
+  { "Get", "ss", "v", bus_driver_handle_get, METHOD_FLAG_NONE },
+  { "GetAll", "s", "a{sv}", bus_driver_handle_get_all, METHOD_FLAG_NONE },
+  { "Set", "ssv", "", bus_driver_handle_set, METHOD_FLAG_NONE },
+  { NULL, NULL, NULL, NULL }
+};
+
 static const MessageHandler introspectable_message_handlers[] = {
-  { "Introspect", "", DBUS_TYPE_STRING_AS_STRING, bus_driver_handle_introspect },
+  { "Introspect", "", DBUS_TYPE_STRING_AS_STRING, bus_driver_handle_introspect,
+    METHOD_FLAG_ANY_PATH },
   { NULL, NULL, NULL, NULL }
 };
 
 static const MessageHandler monitoring_message_handlers[] = {
-  { "BecomeMonitor", "asu", "", bus_driver_handle_become_monitor },
+  { "BecomeMonitor", "asu", "", bus_driver_handle_become_monitor,
+    METHOD_FLAG_PRIVILEGED },
   { NULL, NULL, NULL, NULL }
 };
 
 #ifdef DBUS_ENABLE_VERBOSE_MODE
 static const MessageHandler verbose_message_handlers[] = {
-  { "EnableVerbose", "", "", bus_driver_handle_enable_verbose},
-  { "DisableVerbose", "", "", bus_driver_handle_disable_verbose},
+  { "EnableVerbose", "", "", bus_driver_handle_enable_verbose,
+    METHOD_FLAG_NONE },
+  { "DisableVerbose", "", "", bus_driver_handle_disable_verbose,
+    METHOD_FLAG_NONE },
   { NULL, NULL, NULL, NULL }
 };
 #endif
 
 #ifdef DBUS_ENABLE_STATS
 static const MessageHandler stats_message_handlers[] = {
-  { "GetStats", "", "a{sv}", bus_stats_handle_get_stats },
-  { "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats },
-  { "GetAllMatchRules", "", "a{sas}", bus_stats_handle_get_all_match_rules },
+  { "GetStats", "", "a{sv}", bus_stats_handle_get_stats,
+    METHOD_FLAG_NONE },
+  { "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats,
+    METHOD_FLAG_NONE },
+  { "GetAllMatchRules", "", "a{sas}", bus_stats_handle_get_all_match_rules,
+    METHOD_FLAG_NONE },
   { NULL, NULL, NULL, NULL }
 };
 #endif
 
+static const MessageHandler peer_message_handlers[] = {
+  { "GetMachineId", "", "s", bus_driver_handle_get_machine_id,
+    METHOD_FLAG_ANY_PATH },
+  { "Ping", "", "", bus_driver_handle_ping, METHOD_FLAG_ANY_PATH },
+  { NULL, NULL, NULL, NULL }
+};
+
+typedef enum
+{
+  /* Various older interfaces were available at every object path. We have to
+   * preserve that behaviour for backwards compatibility, but we can at least
+   * stop doing that for newly added interfaces:
+   * <https://bugs.freedesktop.org/show_bug.cgi?id=101256>
+   * Introspectable and Peer are also useful at all object paths. */
+  INTERFACE_FLAG_ANY_PATH = (1 << 0),
+
+  /* Set this flag for interfaces that should not show up in the
+   * Interfaces property. */
+  INTERFACE_FLAG_UNINTERESTING = (1 << 1),
+
+  INTERFACE_FLAG_NONE = 0
+} InterfaceFlags;
+
 typedef struct {
   const char *name;
   const MessageHandler *message_handlers;
   const char *extra_introspection;
+  InterfaceFlags flags;
+  const PropertyHandler *property_handlers;
 } InterfaceHandler;
 
 /* These should ideally be sorted by frequency of use, although it
@@ -2193,15 +2672,42 @@ static InterfaceHandler interface_handlers[] = {
     "    </signal>\n"
     "    <signal name=\"NameAcquired\">\n"
     "      <arg type=\"s\"/>\n"
-    "    </signal>\n" },
-  { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL },
-  { DBUS_INTERFACE_MONITORING, monitoring_message_handlers, NULL },
+    "    </signal>\n",
+    /* Not in the Interfaces property because if you can get the properties
+     * of the o.fd.DBus interface, then you certainly have the o.fd.DBus
+     * interface, so there is little point in listing it explicitly.
+     * Partially available at all paths for backwards compatibility. */
+    INTERFACE_FLAG_ANY_PATH | INTERFACE_FLAG_UNINTERESTING,
+    dbus_property_handlers },
+  { DBUS_INTERFACE_PROPERTIES, properties_message_handlers,
+    "    <signal name=\"PropertiesChanged\">\n"
+    "      <arg type=\"s\" name=\"interface_name\"/>\n"
+    "      <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"
+    "      <arg type=\"as\" name=\"invalidated_properties\"/>\n"
+    "    </signal>\n",
+    /* Not in the Interfaces property because if you can get the properties
+     * of the o.fd.DBus interface, then you certainly have Properties. */
+    INTERFACE_FLAG_UNINTERESTING },
+  { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL,
+    /* Not in the Interfaces property because introspection isn't really a
+     * feature in the same way as e.g. Monitoring.
+     * Available at all paths so tools like d-feet can start from "/". */
+    INTERFACE_FLAG_ANY_PATH | INTERFACE_FLAG_UNINTERESTING },
+  { DBUS_INTERFACE_MONITORING, monitoring_message_handlers, NULL,
+    INTERFACE_FLAG_NONE },
 #ifdef DBUS_ENABLE_VERBOSE_MODE
-  { DBUS_INTERFACE_VERBOSE, verbose_message_handlers, NULL },
+  { DBUS_INTERFACE_VERBOSE, verbose_message_handlers, NULL,
+    INTERFACE_FLAG_NONE },
 #endif
 #ifdef DBUS_ENABLE_STATS
-  { BUS_INTERFACE_STATS, stats_message_handlers, NULL },
+  { BUS_INTERFACE_STATS, stats_message_handlers, NULL,
+    INTERFACE_FLAG_NONE },
 #endif
+  { DBUS_INTERFACE_PEER, peer_message_handlers, NULL,
+    /* Not in the Interfaces property because it's a pseudo-interface
+     * on all object paths of all connections, rather than a feature of the
+     * bus driver object. */
+    INTERFACE_FLAG_ANY_PATH | INTERFACE_FLAG_UNINTERESTING },
   { NULL, NULL, NULL }
 };
 
@@ -2241,10 +2747,13 @@ write_args_for_direction (DBusString *xml,
 }
 
 dbus_bool_t
-bus_driver_generate_introspect_string (DBusString *xml)
+bus_driver_generate_introspect_string (DBusString *xml,
+                                       dbus_bool_t is_canonical_path,
+                                       DBusMessage *message)
 {
   const InterfaceHandler *ih;
   const MessageHandler *mh;
+  const PropertyHandler *ph;
 
   if (!_dbus_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
     return FALSE;
@@ -2253,6 +2762,9 @@ bus_driver_generate_introspect_string (DBusString *xml)
 
   for (ih = interface_handlers; ih->name != NULL; ih++)
     {
+      if (!(is_canonical_path || (ih->flags & INTERFACE_FLAG_ANY_PATH)))
+        continue;
+
       if (!_dbus_string_append_printf (xml, "  <interface name=\"%s\">\n",
                                        ih->name))
         return FALSE;
@@ -2273,6 +2785,20 @@ bus_driver_generate_introspect_string (DBusString *xml)
             return FALSE;
         }
 
+      for (ph = ih->property_handlers; ph != NULL && ph->name != NULL; ph++)
+        {
+          /* We only have constant properties so far, so hard-code that bit */
+          if (!_dbus_string_append_printf (xml,
+                                           "    <property name=\"%s\" type=\"%s\" access=\"read\">\n",
+                                           ph->name, ph->type))
+            return FALSE;
+
+          if (!_dbus_string_append (xml,
+                                    "      <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n"
+                                    "    </property>\n"))
+            return FALSE;
+        }
+
       if (ih->extra_introspection != NULL &&
           !_dbus_string_append (xml, ih->extra_introspection))
         return FALSE;
@@ -2281,13 +2807,35 @@ bus_driver_generate_introspect_string (DBusString *xml)
         return FALSE;
     }
 
+  if (message != NULL)
+    {
+      /* Make the bus driver object path discoverable */
+      if (dbus_message_has_path (message, "/"))
+        {
+          if (!_dbus_string_append (xml,
+                "  <node name=\"org/freedesktop/DBus\"/>\n"))
+            return FALSE;
+        }
+      else if (dbus_message_has_path (message, "/org"))
+        {
+          if (!_dbus_string_append (xml,
+                "  <node name=\"freedesktop/DBus\"/>\n"))
+            return FALSE;
+        }
+      else if (dbus_message_has_path (message, "/org/freedesktop"))
+        {
+          if (!_dbus_string_append (xml, "  <node name=\"DBus\"/>\n"))
+            return FALSE;
+        }
+    }
+
   if (!_dbus_string_append (xml, "</node>\n"))
     return FALSE;
 
   return TRUE;
 }
 
-static dbus_bool_t
+static BusResult
 bus_driver_handle_introspect (DBusConnection *connection,
                               BusTransaction *transaction,
                               DBusMessage    *message,
@@ -2296,6 +2844,7 @@ bus_driver_handle_introspect (DBusConnection *connection,
   DBusString xml;
   DBusMessage *reply;
   const char *v_STRING;
+  dbus_bool_t is_canonical_path;
 
   _dbus_verbose ("Introspect() on bus driver\n");
 
@@ -2307,16 +2856,18 @@ bus_driver_handle_introspect (DBusConnection *connection,
                               DBUS_TYPE_INVALID))
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
   if (!_dbus_string_init (&xml))
     {
       BUS_SET_OOM (error);
-      return FALSE;
+      return BUS_RESULT_FALSE;
     }
 
-  if (!bus_driver_generate_introspect_string (&xml))
+  is_canonical_path = dbus_message_has_path (message, DBUS_PATH_DBUS);
+
+  if (!bus_driver_generate_introspect_string (&xml, is_canonical_path, message))
     goto oom;
 
   v_STRING = _dbus_string_get_const_data (&xml);
@@ -2336,7 +2887,7 @@ bus_driver_handle_introspect (DBusConnection *connection,
   dbus_message_unref (reply);
   _dbus_string_free (&xml);
 
-  return TRUE;
+  return BUS_RESULT_TRUE;
 
  oom:
   BUS_SET_OOM (error);
@@ -2346,42 +2897,10 @@ bus_driver_handle_introspect (DBusConnection *connection,
 
   _dbus_string_free (&xml);
 
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
-/*
- * Set @error and return FALSE if the message is not directed to the
- * dbus-daemon by its canonical object path. This is hardening against
- * system services with poorly-written security policy files, which
- * might allow sending dangerously broad equivalence classes of messages
- * such as "anything with this assumed-to-be-safe object path".
- *
- * dbus-daemon is unusual in that it normally ignores the object path
- * of incoming messages; we need to keep that behaviour for the "read"
- * read-only method calls like GetConnectionUnixUser for backwards
- * compatibility, but it seems safer to be more restrictive for things
- * intended to be root-only or privileged-developers-only.
- *
- * It is possible that there are other system services with the same
- * quirk as dbus-daemon.
- */
-dbus_bool_t
-bus_driver_check_message_is_for_us (DBusMessage *message,
-                                    DBusError   *error)
-{
-  if (!dbus_message_has_path (message, DBUS_PATH_DBUS))
-    {
-      dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
-          "Method '%s' is only available at the canonical object path '%s'",
-          dbus_message_get_member (message), DBUS_PATH_DBUS);
-
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-dbus_bool_t
+BusResult
 bus_driver_handle_message (DBusConnection *connection,
                            BusTransaction *transaction,
                           DBusMessage    *message,
@@ -2391,6 +2910,7 @@ bus_driver_handle_message (DBusConnection *connection,
   const InterfaceHandler *ih;
   const MessageHandler *mh;
   dbus_bool_t found_interface = FALSE;
+  dbus_bool_t is_canonical_path;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -2399,6 +2919,15 @@ bus_driver_handle_message (DBusConnection *connection,
       BusContext *context;
       DBusConnection *systemd;
 
+      /* This is a directed signal, not a method call, so the log message
+       * is a little weird (it talks about "calling" ActivationFailure),
+       * but it's close enough */
+      if (!bus_driver_check_caller_is_privileged (connection,
+                                                  transaction,
+                                                  message,
+                                                  error))
+        return BUS_RESULT_FALSE;
+
       context = bus_connection_get_context (connection);
       systemd = bus_driver_get_owner_of_name (connection,
           "org.freedesktop.systemd1");
@@ -2414,16 +2943,24 @@ bus_driver_handle_message (DBusConnection *connection,
                            attacker ? attacker : "(unauthenticated)",
                            bus_connection_get_loginfo (connection));
           /* ignore it */
-          return TRUE;
+          return BUS_RESULT_TRUE;
+        }
+
+      if (!bus_context_get_systemd_activation (context))
+        {
+          bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
+                           "Ignoring unexpected ActivationFailure message "
+                           "while not using systemd activation");
+          return BUS_RESULT_FALSE;
         }
 
-      return dbus_activation_systemd_failure(bus_context_get_activation(context), message);
+      return dbus_activation_systemd_failure(bus_context_get_activation(context), message) == TRUE ? BUS_RESULT_TRUE : BUS_RESULT_FALSE;
     }
 
   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
     {
       _dbus_verbose ("Driver got a non-method-call message, ignoring\n");
-      return TRUE; /* we just ignore this */
+      return BUS_RESULT_TRUE; /* we just ignore this */
     }
 
   /* may be NULL, which means "any interface will do" */
@@ -2439,8 +2976,13 @@ bus_driver_handle_message (DBusConnection *connection,
   _dbus_assert (dbus_message_get_sender (message) != NULL ||
                 strcmp (name, "Hello") == 0);
 
+  is_canonical_path = dbus_message_has_path (message, DBUS_PATH_DBUS);
+
   for (ih = interface_handlers; ih->name != NULL; ih++)
     {
+      if (!(is_canonical_path || (ih->flags & INTERFACE_FLAG_ANY_PATH)))
+        continue;
+
       if (interface != NULL && strcmp (interface, ih->name) != 0)
         continue;
 
@@ -2453,6 +2995,24 @@ bus_driver_handle_message (DBusConnection *connection,
 
           _dbus_verbose ("Found driver handler for %s\n", name);
 
+          if ((mh->flags & METHOD_FLAG_PRIVILEGED) &&
+              !bus_driver_check_caller_is_privileged (connection, transaction,
+                                                      message, error))
+            {
+              _DBUS_ASSERT_ERROR_IS_SET (error);
+              return BUS_RESULT_FALSE;
+            }
+
+          if (!(is_canonical_path || (mh->flags & METHOD_FLAG_ANY_PATH)))
+            {
+              _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+              dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+                  "Method '%s' is only available at the canonical object path '%s'",
+                  dbus_message_get_member (message), DBUS_PATH_DBUS);
+              _DBUS_ASSERT_ERROR_IS_SET (error);
+              return BUS_RESULT_FALSE;
+            }
+
           if (!dbus_message_has_signature (message, mh->in_args))
             {
               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -2465,20 +3025,23 @@ bus_driver_handle_message (DBusConnection *connection,
                               name, dbus_message_get_signature (message),
                               mh->in_args);
               _DBUS_ASSERT_ERROR_IS_SET (error);
-              return FALSE;
+              return BUS_RESULT_FALSE;
             }
 
-          if ((* mh->handler) (connection, transaction, message, error))
-            {
-              _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-              _dbus_verbose ("Driver handler succeeded\n");
-              return TRUE;
-            }
-          else
+          switch ((* mh->handler) (connection, transaction, message, error))
             {
-              _DBUS_ASSERT_ERROR_IS_SET (error);
-              _dbus_verbose ("Driver handler returned failure\n");
-              return FALSE;
+              case BUS_RESULT_TRUE:
+                _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+                _dbus_verbose ("Driver handler succeeded\n");
+                return BUS_RESULT_TRUE;
+              case BUS_RESULT_FALSE:
+                _DBUS_ASSERT_ERROR_IS_SET (error);
+                _dbus_verbose ("Driver handler returned failure\n");
+                return BUS_RESULT_FALSE;
+              case BUS_RESULT_LATER:
+                _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+                _dbus_verbose ("Driver handler delayed message processing due to policy check\n");
+                return BUS_RESULT_LATER;
             }
         }
     }
@@ -2490,7 +3053,7 @@ bus_driver_handle_message (DBusConnection *connection,
                   "%s does not understand message %s",
                   DBUS_SERVICE_DBUS, name);
 
-  return FALSE;
+  return BUS_RESULT_FALSE;
 }
 
 void
@@ -2500,3 +3063,298 @@ bus_driver_remove_connection (DBusConnection *connection)
    * with the bus driver.
    */
 }
+
+static dbus_bool_t
+features_getter (BusContext      *context,
+                 DBusMessageIter *variant_iter)
+{
+  DBusMessageIter arr_iter;
+
+  if (!dbus_message_iter_open_container (variant_iter, DBUS_TYPE_ARRAY,
+                                         DBUS_TYPE_STRING_AS_STRING,
+                                         &arr_iter))
+    return FALSE;
+
+  if (bus_apparmor_enabled ())
+    {
+      const char *s = "AppArmor";
+
+      if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, &s))
+        goto abandon;
+    }
+
+  if (bus_selinux_enabled ())
+    {
+      const char *s = "SELinux";
+
+      if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, &s))
+        goto abandon;
+    }
+
+  if (bus_context_get_systemd_activation (context))
+    {
+      const char *s = "SystemdActivation";
+
+      if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, &s))
+        goto abandon;
+    }
+
+  return dbus_message_iter_close_container (variant_iter, &arr_iter);
+
+abandon:
+  dbus_message_iter_abandon_container (variant_iter, &arr_iter);
+  return FALSE;
+}
+
+static dbus_bool_t
+interfaces_getter (BusContext      *context,
+                   DBusMessageIter *variant_iter)
+{
+  DBusMessageIter arr_iter;
+  const InterfaceHandler *ih;
+
+  if (!dbus_message_iter_open_container (variant_iter, DBUS_TYPE_ARRAY,
+                                         DBUS_TYPE_STRING_AS_STRING,
+                                         &arr_iter))
+    return FALSE;
+
+  for (ih = interface_handlers; ih->name != NULL; ih++)
+    {
+      if (ih->flags & INTERFACE_FLAG_UNINTERESTING)
+        continue;
+
+      if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING,
+                                           &ih->name))
+        goto abandon;
+    }
+
+  return dbus_message_iter_close_container (variant_iter, &arr_iter);
+
+abandon:
+  dbus_message_iter_abandon_container (variant_iter, &arr_iter);
+  return FALSE;
+}
+
+static const InterfaceHandler *
+bus_driver_find_interface (const char  *name,
+                           dbus_bool_t  canonical_path,
+                           DBusError   *error)
+{
+  const InterfaceHandler *ih;
+
+  for (ih = interface_handlers; ih->name != NULL; ih++)
+    {
+      if (!(canonical_path || (ih->flags & INTERFACE_FLAG_ANY_PATH)))
+        continue;
+
+      if (strcmp (name, ih->name) == 0)
+        return ih;
+    }
+
+  dbus_set_error (error, DBUS_ERROR_UNKNOWN_INTERFACE,
+                  "Interface \"%s\" not found", name);
+  return NULL;
+}
+
+static const PropertyHandler *
+interface_handler_find_property (const InterfaceHandler *ih,
+                                 const char             *name,
+                                 DBusError              *error)
+{
+  const PropertyHandler *ph;
+
+  for (ph = ih->property_handlers; ph != NULL && ph->name != NULL; ph++)
+    {
+      if (strcmp (name, ph->name) == 0)
+        return ph;
+    }
+
+  dbus_set_error (error, DBUS_ERROR_UNKNOWN_PROPERTY,
+                  "Property \"%s.%s\" not found", ih->name, name);
+  return NULL;
+}
+
+static dbus_bool_t
+bus_driver_handle_get (DBusConnection *connection,
+                       BusTransaction *transaction,
+                       DBusMessage    *message,
+                       DBusError      *error)
+{
+  const InterfaceHandler *ih;
+  const PropertyHandler *handler;
+  const char *iface;
+  const char *prop;
+  BusContext *context;
+  DBusMessage *reply = NULL;
+  DBusMessageIter iter;
+  DBusMessageIter var_iter;
+
+  /* The message signature has already been checked for us,
+   * so this should always succeed. */
+  if (!dbus_message_get_args (message, error,
+                              DBUS_TYPE_STRING, &iface,
+                              DBUS_TYPE_STRING, &prop,
+                              DBUS_TYPE_INVALID))
+    return FALSE;
+
+  /* We only implement Properties on /org/freedesktop/DBus so far. */
+  ih = bus_driver_find_interface (iface, TRUE, error);
+
+  if (ih == NULL)
+    return FALSE;
+
+  handler = interface_handler_find_property (ih, prop, error);
+
+  if (handler == NULL)
+    return FALSE;
+
+  context = bus_transaction_get_context (transaction);
+
+  reply = dbus_message_new_method_return (message);
+
+  if (reply == NULL)
+    goto oom;
+
+  dbus_message_iter_init_append (reply, &iter);
+
+  if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT,
+                                         handler->type, &var_iter))
+    goto oom;
+
+  if (!handler->getter (context, &var_iter))
+    {
+      dbus_message_iter_abandon_container (&iter, &var_iter);
+      goto oom;
+    }
+
+  if (!dbus_message_iter_close_container (&iter, &var_iter))
+    goto oom;
+
+  if (!bus_transaction_send_from_driver (transaction, connection, reply))
+    goto oom;
+
+  dbus_message_unref (reply);
+  return TRUE;
+
+oom:
+  if (reply != NULL)
+    dbus_message_unref (reply);
+
+  BUS_SET_OOM (error);
+  return FALSE;
+}
+
+static dbus_bool_t
+bus_driver_handle_get_all (DBusConnection *connection,
+                           BusTransaction *transaction,
+                           DBusMessage    *message,
+                           DBusError      *error)
+{
+  const InterfaceHandler *ih;
+  const char *iface;
+  const PropertyHandler *ph;
+  DBusMessageIter reply_iter;
+  DBusMessageIter array_iter;
+  BusContext *context;
+  DBusMessage *reply = NULL;
+
+  /* The message signature has already been checked for us,
+   * so this should always succeed. */
+  if (!dbus_message_get_args (message, error,
+                              DBUS_TYPE_STRING, &iface,
+                              DBUS_TYPE_INVALID))
+    return FALSE;
+
+  /* We only implement Properties on /org/freedesktop/DBus so far. */
+  ih = bus_driver_find_interface (iface, TRUE, error);
+
+  if (ih == NULL)
+    return FALSE;
+
+  context = bus_transaction_get_context (transaction);
+
+  reply = _dbus_asv_new_method_return (message, &reply_iter, &array_iter);
+
+  if (reply == NULL)
+    goto oom;
+
+  for (ph = ih->property_handlers; ph != NULL && ph->name != NULL; ph++)
+    {
+      DBusMessageIter entry_iter;
+      DBusMessageIter var_iter;
+
+      if (!_dbus_asv_open_entry (&array_iter, &entry_iter, ph->name,
+                                 ph->type, &var_iter))
+        goto oom_abandon_message;
+
+      if (!ph->getter (context, &var_iter))
+        {
+          _dbus_asv_abandon_entry (&array_iter, &entry_iter, &var_iter);
+          goto oom_abandon_message;
+        }
+
+      if (!_dbus_asv_close_entry (&array_iter, &entry_iter, &var_iter))
+        goto oom_abandon_message;
+    }
+
+  if (!_dbus_asv_close (&reply_iter, &array_iter))
+    goto oom;
+
+  if (!bus_transaction_send_from_driver (transaction, connection, reply))
+    goto oom;
+
+  dbus_message_unref (reply);
+  return TRUE;
+
+oom_abandon_message:
+  _dbus_asv_abandon (&reply_iter, &array_iter);
+  /* fall through */
+oom:
+  if (reply != NULL)
+    dbus_message_unref (reply);
+
+  BUS_SET_OOM (error);
+  return FALSE;
+}
+
+static dbus_bool_t
+bus_driver_handle_set (DBusConnection *connection,
+                       BusTransaction *transaction,
+                       DBusMessage    *message,
+                       DBusError      *error)
+{
+  const InterfaceHandler *ih;
+  const char *iface;
+  const char *prop;
+  const PropertyHandler *handler;
+  DBusMessageIter iter;
+
+  /* We already checked this in bus_driver_handle_message() */
+  _dbus_assert (dbus_message_has_signature (message, "ssv"));
+
+  if (!dbus_message_iter_init (message, &iter))
+    _dbus_assert_not_reached ("Message type was already checked to be 'ssv'");
+
+  dbus_message_iter_get_basic (&iter, &iface);
+
+  if (!dbus_message_iter_next (&iter))
+    _dbus_assert_not_reached ("Message type was already checked to be 'ssv'");
+
+  dbus_message_iter_get_basic (&iter, &prop);
+
+  /* We only implement Properties on /org/freedesktop/DBus so far. */
+  ih = bus_driver_find_interface (iface, TRUE, error);
+
+  if (ih == NULL)
+    return FALSE;
+
+  handler = interface_handler_find_property (ih, prop, error);
+
+  if (handler == NULL)
+    return FALSE;
+
+  /* We don't implement any properties that can be set yet. */
+  dbus_set_error (error, DBUS_ERROR_PROPERTY_READ_ONLY,
+                  "Property '%s.%s' cannot be set", iface, prop);
+  return FALSE;
+}