[daemon-fix] Fixed sending daemon match rules for kdbus broadcasts
[platform/upstream/dbus.git] / bus / dispatch.c
index f491ef4..a7d4c37 100644 (file)
@@ -1,12 +1,13 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dispatch.c  Message dispatcher
  *
  * Copyright (C) 2003  CodeFactory AB
  * Copyright (C) 2003, 2004, 2005  Red Hat, Inc.
  * Copyright (C) 2004  Imendio HB
+ * Copyright (C) 2013  Samsung Electronics
  *
  * Licensed under the Academic Free License version 2.1
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
+#include <config.h>
 #include "dispatch.h"
 #include "connection.h"
 #include "driver.h"
 #include "signals.h"
 #include "test.h"
 #include <dbus/dbus-internals.h>
+#include <dbus/dbus-misc.h>
 #include <string.h>
+#ifdef ENABLE_KDBUS_TRANSPORT
+#include "kdbus-d.h"
+#endif
+
+#ifdef HAVE_UNIX_FD_PASSING
+#include <dbus/dbus-sysdeps-unix.h>
+#include <unistd.h>
+#endif
+
+/* This is hard-coded in the files in valid-config-files-*. We have to use
+ * the debug-pipe transport because the tests in this file require that
+ * dbus_connection_open_private() does not block. */
+#define TEST_DEBUG_PIPE "debug-pipe:name=test-server"
 
 static dbus_bool_t
 send_one_message (DBusConnection *connection,
@@ -51,7 +67,11 @@ send_one_message (DBusConnection *connection,
                                           message,
                                           NULL))
     return TRUE; /* silently don't send it */
-  
+
+  if (dbus_message_contains_unix_fds(message) &&
+      !dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD))
+    return TRUE; /* silently don't send it */
+
   if (!bus_transaction_send (transaction,
                              connection,
                              message))
@@ -86,10 +106,39 @@ bus_dispatch_matches (BusTransaction *transaction,
   _dbus_assert (sender == NULL || bus_connection_is_active (sender));
   _dbus_assert (dbus_message_get_sender (message) != NULL);
 
+  context = bus_transaction_get_context (transaction);
+
+  /* First, send the message to the addressed_recipient, if there is one. */
+  if (addressed_recipient != NULL)
+    {
+      if (!bus_context_check_security_policy (context, transaction,
+                                              sender, addressed_recipient,
+                                              addressed_recipient,
+                                              message, error))
+        return FALSE;
+
+      if (dbus_message_contains_unix_fds (message) &&
+          !dbus_connection_can_send_type (addressed_recipient,
+                                          DBUS_TYPE_UNIX_FD))
+        {
+          dbus_set_error (error,
+                          DBUS_ERROR_NOT_SUPPORTED,
+                          "Tried to send message with Unix file descriptors"
+                          "to a client that doesn't support that.");
+          return FALSE;
+      }
+
+      /* Dispatch the message */
+      if (!bus_transaction_send (transaction, addressed_recipient, message))
+        {
+          BUS_SET_OOM (error);
+          return FALSE;
+        }
+    }
+
+  /* Now dispatch to others who look interested in this message */
   connections = bus_transaction_get_connections (transaction);
-  
   dbus_error_init (&tmp_error);
-  context = bus_transaction_get_context (transaction);
   matchmaker = bus_context_get_matchmaker (context);
 
   recipients = NULL;
@@ -116,7 +165,7 @@ bus_dispatch_matches (BusTransaction *transaction,
     }
 
   _dbus_list_clear (&recipients);
-  
+
   if (dbus_error_is_set (&tmp_error))
     {
       dbus_move_error (&tmp_error, error);
@@ -136,25 +185,25 @@ bus_dispatch (DBusConnection *connection,
   BusContext *context;
   DBusHandlerResult result;
   DBusConnection *addressed_recipient;
-  
+
   result = DBUS_HANDLER_RESULT_HANDLED;
-  
+
   transaction = NULL;
   addressed_recipient = NULL;
   dbus_error_init (&error);
-  
+
   context = bus_connection_get_context (connection);
   _dbus_assert (context != NULL);
-  
+
   /* If we can't even allocate an OOM error, we just go to sleep
    * until we can.
    */
   while (!bus_connection_preallocate_oom_error (connection))
     _dbus_wait_for_memory ();
-  
+
   /* Ref connection in case we disconnect it at some point in here */
   dbus_connection_ref (connection);
-  
+
   service_name = dbus_message_get_destination (message);
 
 #ifdef DBUS_ENABLE_VERBOSE_MODE
@@ -164,7 +213,7 @@ bus_dispatch (DBusConnection *connection,
     interface_name = dbus_message_get_interface (message);
     member_name = dbus_message_get_member (message);
     error_name = dbus_message_get_error_name (message);
-    
+
     _dbus_verbose ("DISPATCH: %s %s %s to %s\n",
                    interface_name ? interface_name : "(no interface)",
                    member_name ? member_name : "(no member)",
@@ -172,7 +221,15 @@ bus_dispatch (DBusConnection *connection,
                    service_name ? service_name : "peer");
   }
 #endif /* DBUS_ENABLE_VERBOSE_MODE */
-  
+
+  /* Create our transaction */
+  transaction = bus_transaction_new (context);
+  if (transaction == NULL)
+    {
+      BUS_SET_OOM (&error);
+      goto out;
+    }
+
   /* If service_name is NULL, if it's a signal we send it to all
    * connections with a match rule. If it's not a signal, there
    * are some special cases here but mostly we just bail out.
@@ -195,18 +252,25 @@ bus_dispatch (DBusConnection *connection,
           result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
           goto out;
         }
+
+#ifdef ENABLE_KDBUS_TRANSPORT
+      if(bus_context_is_kdbus(context))
+      {
+          if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
+          {
+              handleNameOwnerChanged(message, transaction, connection);
+              goto out;
+          }
+      }
+#endif
     }
-  
-  /* Create our transaction */
-  transaction = bus_transaction_new (context);
-  if (transaction == NULL)
-    {
-      BUS_SET_OOM (&error);
-      goto out;
-    }
-  
+
+#ifdef ENABLE_KDBUS_TRANSPORT
   /* Assign a sender to the message */
-  if (bus_connection_is_active (connection))
+  if(bus_context_is_kdbus(context) == FALSE)  //if using kdbus, sender must be set on library side
+#endif
+  {
+    if (bus_connection_is_active (connection))
     {
       sender = bus_connection_get_name (connection);
       _dbus_assert (sender != NULL);
@@ -224,7 +288,8 @@ bus_dispatch (DBusConnection *connection,
        */
       service_name = dbus_message_get_destination (message);
     }
-  
+  }
+
   if (service_name &&
       strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
     {
@@ -252,13 +317,17 @@ bus_dispatch (DBusConnection *connection,
       BusRegistry *registry;
 
       _dbus_assert (service_name != NULL);
-      
+
       registry = bus_connection_get_registry (connection);
-      
+
       _dbus_string_init_const (&service_string, service_name);
       service = bus_registry_lookup (registry, &service_string);
 
+#ifdef ENABLE_KDBUS_TRANSPORT
+      if (dbus_message_get_auto_start (message) && (service == NULL || bus_service_get_is_kdbus_starter(service)))
+#else
       if (service == NULL && dbus_message_get_auto_start (message))
+#endif
         {
           BusActivation *activation;
           /* We can't do the security policy check here, since the addressed
@@ -274,7 +343,7 @@ bus_dispatch (DBusConnection *connection,
               _dbus_verbose ("bus_activation_activate_service() failed: %s\n", error.name);
               goto out;
             }
-          
+
           goto out;
         }
       else if (service == NULL)
@@ -289,28 +358,16 @@ bus_dispatch (DBusConnection *connection,
         {
           addressed_recipient = bus_service_get_primary_owners_connection (service);
           _dbus_assert (addressed_recipient != NULL);
-          
-          if (!bus_context_check_security_policy (context, transaction,
-                                                  connection, addressed_recipient,
-                                                  addressed_recipient,
-                                                  message, &error))
-            goto out;
-          
-          /* Dispatch the message */
-          if (!bus_transaction_send (transaction, addressed_recipient, message))
-            {
-              BUS_SET_OOM (&error);
-              goto out;
-            }
         }
     }
 
-  /* Now match the messages against any match rules, which will send
-   * out signals and such. addressed_recipient may == NULL.
+  /* Now send the message to its destination (or not, if
+   * addressed_recipient == NULL), and match it against other connections'
+   * match rules.
    */
   if (!bus_dispatch_matches (transaction, connection, addressed_recipient, message, &error))
     goto out;
-  
+
  out:
   if (dbus_error_is_set (&error))
     {
@@ -342,7 +399,7 @@ bus_dispatch (DBusConnection *connection,
                                                  &error, message))
             {
               bus_connection_send_oom_error (connection, message);
-              
+
               /* cancel transaction due to OOM */
               if (transaction != NULL)
                 {
@@ -351,8 +408,8 @@ bus_dispatch (DBusConnection *connection,
                 }
             }
         }
-     
-      
+
+
       dbus_error_free (&error);
     }
 
@@ -376,12 +433,12 @@ bus_dispatch_message_filter (DBusConnection     *connection,
 
 dbus_bool_t
 bus_dispatch_add_connection (DBusConnection *connection)
-{  
+{
   if (!dbus_connection_add_filter (connection,
                                    bus_dispatch_message_filter,
                                    NULL, NULL))
     return FALSE;
-  
+
   return TRUE;
 }
 
@@ -396,7 +453,7 @@ bus_dispatch_remove_connection (DBusConnection *connection)
                                  NULL);
 }
 
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
 
 #include <stdio.h>
 
@@ -418,7 +475,7 @@ block_connection_until_message_from_bus (BusContext     *context,
                                          const char     *what_is_expected)
 {
   _dbus_verbose ("expecting: %s\n", what_is_expected);
-  
+
   while (dbus_connection_get_dispatch_status (connection) ==
          DBUS_DISPATCH_COMPLETE &&
          dbus_connection_get_is_connected (connection))
@@ -527,13 +584,13 @@ check_service_owner_changed_foreach (DBusConnection *connection,
   DBusError error;
   const char *service_name, *old_owner, *new_owner;
 
-  if (d->expected_kind == SERVICE_CREATED 
+  if (d->expected_kind == SERVICE_CREATED
       && connection == d->skip_connection)
     return TRUE;
 
   dbus_error_init (&error);
   d->failed = TRUE;
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -567,7 +624,7 @@ check_service_owner_changed_foreach (DBusConnection *connection,
           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
             {
               dbus_error_free (&error);
-              _dbus_wait_for_memory ();              
+              _dbus_wait_for_memory ();
               goto reget_service_info_data;
             }
           else
@@ -593,7 +650,7 @@ check_service_owner_changed_foreach (DBusConnection *connection,
           goto out;
         }
 
-      if (*service_name == ':' && new_owner[0] 
+      if (*service_name == ':' && new_owner[0]
           && strcmp (service_name, new_owner) != 0)
         {
           _dbus_warn ("inconsistent ServiceOwnedChanged message (\"%s\" [ %s -> %s ])\n",
@@ -603,10 +660,10 @@ check_service_owner_changed_foreach (DBusConnection *connection,
     }
 
   d->failed = FALSE;
-  
+
  out:
   dbus_error_free (&error);
-  
+
   if (message)
     dbus_message_unref (message);
 
@@ -623,7 +680,7 @@ kill_client_connection (BusContext     *context,
   CheckServiceOwnerChangedData socd;
 
   _dbus_verbose ("killing connection %p\n", connection);
-  
+
   s = dbus_bus_get_unique_name (connection);
   _dbus_assert (s != NULL);
 
@@ -631,36 +688,36 @@ kill_client_connection (BusContext     *context,
     _dbus_wait_for_memory ();
 
   dbus_connection_ref (connection);
-  
+
   /* kick in the disconnect handler that unrefs the connection */
   dbus_connection_close (connection);
 
   bus_test_run_everything (context);
-  
+
   _dbus_assert (bus_test_client_listed (connection));
-  
+
   /* Run disconnect handler in test.c */
   if (bus_connection_dispatch_one_message (connection))
     _dbus_assert_not_reached ("something received on connection being killed other than the disconnect");
-  
+
   _dbus_assert (!dbus_connection_get_is_connected (connection));
   dbus_connection_unref (connection);
   connection = NULL;
   _dbus_assert (!bus_test_client_listed (connection));
-  
+
   socd.expected_kind = SERVICE_DELETED;
   socd.expected_service_name = base_service;
   socd.failed = FALSE;
   socd.skip_connection = NULL;
-  
+
   bus_test_clients_foreach (check_service_owner_changed_foreach,
                             &socd);
 
   dbus_free (base_service);
-  
+
   if (socd.failed)
     _dbus_assert_not_reached ("didn't get the expected NameOwnerChanged (deletion) messages");
-  
+
   if (!check_no_leftovers (context))
     _dbus_assert_not_reached ("stuff left in message queues after disconnecting a client");
 }
@@ -670,7 +727,7 @@ kill_client_connection_unchecked (DBusConnection *connection)
 {
   /* This kills the connection without expecting it to affect
    * the rest of the bus.
-   */  
+   */
   _dbus_verbose ("Unchecked kill of connection %p\n", connection);
 
   dbus_connection_ref (connection);
@@ -716,11 +773,10 @@ check_no_leftovers (BusContext *context)
   nmd.failed = FALSE;
   bus_test_clients_foreach (check_no_messages_foreach,
                             &nmd);
-  
+
   if (nmd.failed)
     {
-      _dbus_verbose ("%s: leftover message found\n",
-                     _DBUS_FUNCTION_NAME);
+      _dbus_verbose ("leftover message found\n");
       return FALSE;
     }
   else
@@ -750,7 +806,7 @@ check_hello_message (BusContext     *context,
   name_message = NULL;
 
   _dbus_verbose ("check_hello_message for %p\n", connection);
-  
+
   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                           DBUS_PATH_DBUS,
                                           DBUS_INTERFACE_DBUS,
@@ -760,7 +816,7 @@ check_hello_message (BusContext     *context,
     return TRUE;
 
   dbus_connection_ref (connection); /* because we may get disconnected */
-  
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -769,44 +825,44 @@ check_hello_message (BusContext     *context,
     }
 
   _dbus_assert (dbus_message_has_signature (message, ""));
-  
+
   dbus_message_unref (message);
   message = NULL;
 
   if (!dbus_connection_get_is_connected (connection))
     {
       _dbus_verbose ("connection was disconnected (presumably auth failed)\n");
-      
+
       dbus_connection_unref (connection);
-      
+
       return TRUE;
     }
-  
+
   /* send our message */
   bus_test_run_clients_loop (SEND_PENDING (connection));
 
   if (!dbus_connection_get_is_connected (connection))
     {
       _dbus_verbose ("connection was disconnected (presumably auth failed)\n");
-      
+
       dbus_connection_unref (connection);
-      
+
       return TRUE;
     }
-  
+
   block_connection_until_message_from_bus (context, connection, "reply to Hello");
 
   if (!dbus_connection_get_is_connected (connection))
     {
       _dbus_verbose ("connection was disconnected (presumably auth failed)\n");
-      
+
       dbus_connection_unref (connection);
-      
+
       return TRUE;
     }
 
   dbus_connection_unref (connection);
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -824,7 +880,7 @@ check_hello_message (BusContext     *context,
                   dbus_message_get_sender (message) : "(none)");
       goto out;
     }
-  
+
   if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
     {
       if (dbus_message_is_error (message,
@@ -842,7 +898,7 @@ check_hello_message (BusContext     *context,
   else
     {
       CheckServiceOwnerChangedData socd;
-      
+
       if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
         {
           ; /* good, expected */
@@ -878,14 +934,14 @@ check_hello_message (BusContext     *context,
 
       while (!dbus_bus_set_unique_name (connection, name))
         _dbus_wait_for_memory ();
-      
+
       socd.expected_kind = SERVICE_CREATED;
       socd.expected_service_name = name;
       socd.failed = FALSE;
       socd.skip_connection = connection; /* we haven't done AddMatch so won't get it ourselves */
       bus_test_clients_foreach (check_service_owner_changed_foreach,
                                 &socd);
-      
+
       if (socd.failed)
         goto out;
 
@@ -906,7 +962,7 @@ check_hello_message (BusContext     *context,
                       "NameAcquired");
           goto out;
         }
-      
+
     retry_get_acquired_name:
       if (!dbus_message_get_args (message, &error,
                                   DBUS_TYPE_STRING, &acquired,
@@ -940,20 +996,20 @@ check_hello_message (BusContext     *context,
 
   if (!check_no_leftovers (context))
     goto out;
-  
+
   retval = TRUE;
-  
+
  out:
-  _dbus_verbose ("ending %s retval = %d\n", _DBUS_FUNCTION_NAME, retval);
-  
+  _dbus_verbose ("ending - retval = %d\n", retval);
+
   dbus_error_free (&error);
-  
+
   if (message)
     dbus_message_unref (message);
 
   if (name_message)
     dbus_message_unref (name_message);
-  
+
   return retval;
 }
 
@@ -974,7 +1030,7 @@ check_double_hello_message (BusContext     *context,
   message = NULL;
 
   _dbus_verbose ("check_double_hello_message for %p\n", connection);
-  
+
   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                           DBUS_PATH_DBUS,
                                           DBUS_INTERFACE_DBUS,
@@ -982,7 +1038,7 @@ check_double_hello_message (BusContext     *context,
 
   if (message == NULL)
     return TRUE;
-  
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -1000,15 +1056,15 @@ check_double_hello_message (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
-      
+      _dbus_verbose ("connection was disconnected\n");
+
       dbus_connection_unref (connection);
-      
+
       return TRUE;
     }
 
   dbus_connection_unref (connection);
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -1026,7 +1082,7 @@ check_double_hello_message (BusContext     *context,
                   dbus_message_get_sender (message) : "(none)");
       goto out;
     }
-  
+
   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
     {
       warn_unexpected (connection, message, "method return for Hello");
@@ -1035,15 +1091,15 @@ check_double_hello_message (BusContext     *context,
 
   if (!check_no_leftovers (context))
     goto out;
-  
+
   retval = TRUE;
-  
+
  out:
   dbus_error_free (&error);
-  
+
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -1066,7 +1122,7 @@ check_get_connection_unix_user (BusContext     *context,
   message = NULL;
 
   _dbus_verbose ("check_get_connection_unix_user for %p\n", connection);
-  
+
   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                           DBUS_PATH_DBUS,
                                           DBUS_INTERFACE_DBUS,
@@ -1077,7 +1133,7 @@ check_get_connection_unix_user (BusContext     *context,
 
   base_service_name = dbus_bus_get_unique_name (connection);
 
-  if (!dbus_message_append_args (message, 
+  if (!dbus_message_append_args (message,
                                  DBUS_TYPE_STRING, &base_service_name,
                                  DBUS_TYPE_INVALID))
     {
@@ -1102,10 +1158,10 @@ check_get_connection_unix_user (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
-      
+      _dbus_verbose ("connection was disconnected\n");
+
       dbus_connection_unref (connection);
-      
+
       return TRUE;
     }
 
@@ -1177,10 +1233,10 @@ check_get_connection_unix_user (BusContext     *context,
 
  out:
   dbus_error_free (&error);
-  
+
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -1203,7 +1259,7 @@ check_get_connection_unix_process_id (BusContext     *context,
   message = NULL;
 
   _dbus_verbose ("check_get_connection_unix_process_id for %p\n", connection);
-  
+
   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                           DBUS_PATH_DBUS,
                                           DBUS_INTERFACE_DBUS,
@@ -1214,7 +1270,7 @@ check_get_connection_unix_process_id (BusContext     *context,
 
   base_service_name = dbus_bus_get_unique_name (connection);
 
-  if (!dbus_message_append_args (message, 
+  if (!dbus_message_append_args (message,
                                  DBUS_TYPE_STRING, &base_service_name,
                                  DBUS_TYPE_INVALID))
     {
@@ -1239,10 +1295,10 @@ check_get_connection_unix_process_id (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
-      
+      _dbus_verbose ("connection was disconnected\n");
+
       dbus_connection_unref (connection);
-      
+
       return TRUE;
     }
 
@@ -1264,6 +1320,15 @@ check_get_connection_unix_process_id (BusContext     *context,
         {
           ; /* good, this is a valid response */
         }
+#ifdef DBUS_WIN
+      else if (dbus_message_is_error (message, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN))
+        {
+          /* We are expecting this error, since we know in the test suite we aren't
+           * talking to a client running on UNIX
+           */
+          _dbus_verbose ("Windows correctly does not support GetConnectionUnixProcessID\n");
+        }
+#endif
       else
         {
           warn_unexpected (connection, message, "not this error");
@@ -1273,6 +1338,10 @@ check_get_connection_unix_process_id (BusContext     *context,
     }
   else
     {
+#ifdef DBUS_WIN
+      warn_unexpected (connection, message, "GetConnectionUnixProcessID to fail on Windows");
+      goto out;
+#else
       if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
         {
           ; /* good, expected */
@@ -1304,8 +1373,9 @@ check_get_connection_unix_process_id (BusContext     *context,
               _dbus_warn ("Did not get the expected DBUS_TYPE_UINT32 from GetConnectionUnixProcessID\n");
               goto out;
             }
-        } else {
-
+        }
+      else
+        {
           /* test if returned pid is the same as our own pid
            *
            * @todo It would probably be good to restructure the tests
@@ -1320,6 +1390,7 @@ check_get_connection_unix_process_id (BusContext     *context,
               goto out;
             }
         }
+#endif /* !DBUS_WIN */
     }
 
   if (!check_no_leftovers (context))
@@ -1329,10 +1400,10 @@ check_get_connection_unix_process_id (BusContext     *context,
 
  out:
   dbus_error_free (&error);
-  
+
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -1354,7 +1425,7 @@ check_add_match_all (BusContext     *context,
   message = NULL;
 
   _dbus_verbose ("check_add_match_all for %p\n", connection);
-  
+
   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                           DBUS_PATH_DBUS,
                                           DBUS_INTERFACE_DBUS,
@@ -1370,7 +1441,7 @@ check_add_match_all (BusContext     *context,
       dbus_message_unref (message);
       return TRUE;
     }
-  
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -1381,32 +1452,32 @@ check_add_match_all (BusContext     *context,
   message = NULL;
 
   dbus_connection_ref (connection); /* because we may get disconnected */
-  
+
   /* send our message */
   bus_test_run_clients_loop (SEND_PENDING (connection));
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
-      
+      _dbus_verbose ("connection was disconnected\n");
+
       dbus_connection_unref (connection);
-      
+
       return TRUE;
     }
-  
+
   block_connection_until_message_from_bus (context, connection, "reply to AddMatch");
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
-      
+      _dbus_verbose ("connection was disconnected\n");
+
       dbus_connection_unref (connection);
-      
+
       return TRUE;
     }
 
   dbus_connection_unref (connection);
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -1424,7 +1495,7 @@ check_add_match_all (BusContext     *context,
                   dbus_message_get_sender (message) : "(none)");
       goto out;
     }
-  
+
   if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
     {
       if (dbus_message_is_error (message,
@@ -1456,15 +1527,15 @@ check_add_match_all (BusContext     *context,
 
   if (!check_no_leftovers (context))
     goto out;
-  
+
   retval = TRUE;
-  
+
  out:
   dbus_error_free (&error);
-  
+
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -1479,7 +1550,7 @@ check_hello_connection (BusContext *context)
 
   dbus_error_init (&error);
 
-  connection = dbus_connection_open_private ("debug-pipe:name=test-server", &error);
+  connection = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (connection == NULL)
     {
       _DBUS_ASSERT_ERROR_IS_SET (&error);
@@ -1495,10 +1566,10 @@ check_hello_connection (BusContext *context)
     }
 
   spin_connection_until_authenticated (context, connection);
-  
+
   if (!check_hello_message (context, connection))
     return FALSE;
-  
+
   if (dbus_bus_get_unique_name (connection) == NULL)
     {
       /* We didn't successfully register, so we can't
@@ -1510,7 +1581,7 @@ check_hello_connection (BusContext *context)
     {
       if (!check_add_match_all (context, connection))
         return FALSE;
-      
+
       kill_client_connection (context, connection);
     }
 
@@ -1531,17 +1602,17 @@ check_nonexistent_service_no_auto_start (BusContext     *context,
   dbus_bool_t retval;
   const char *nonexistent = NONEXISTENT_SERVICE_NAME;
   dbus_uint32_t flags;
-  
+
   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                           DBUS_PATH_DBUS,
                                           DBUS_INTERFACE_DBUS,
                                           "StartServiceByName");
-  
+
   if (message == NULL)
     return TRUE;
 
   dbus_message_set_auto_start (message, FALSE);
-  
+
   flags = 0;
   if (!dbus_message_append_args (message,
                                  DBUS_TYPE_STRING, &nonexistent,
@@ -1551,7 +1622,7 @@ check_nonexistent_service_no_auto_start (BusContext     *context,
       dbus_message_unref (message);
       return TRUE;
     }
-  
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -1567,12 +1638,12 @@ check_nonexistent_service_no_auto_start (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
       return TRUE;
     }
-  
+
   retval = FALSE;
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -1592,7 +1663,7 @@ check_nonexistent_service_no_auto_start (BusContext     *context,
                       dbus_message_get_sender (message) : "(none)");
           goto out;
         }
-      
+
       if (dbus_message_is_error (message,
                                  DBUS_ERROR_NO_MEMORY))
         {
@@ -1617,11 +1688,11 @@ check_nonexistent_service_no_auto_start (BusContext     *context,
     }
 
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -1635,15 +1706,15 @@ check_nonexistent_service_auto_start (BusContext     *context,
   DBusMessage *message;
   dbus_uint32_t serial;
   dbus_bool_t retval;
-    
+
   message = dbus_message_new_method_call (NONEXISTENT_SERVICE_NAME,
                                           "/org/freedesktop/TestSuite",
                                           "org.freedesktop.TestSuite",
                                           "Echo");
-  
+
   if (message == NULL)
     return TRUE;
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -1659,12 +1730,12 @@ check_nonexistent_service_auto_start (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
       return TRUE;
     }
-  
+
   retval = FALSE;
-  
+
   message = pop_message_waiting_for_memory (connection);
 
   if (message == NULL)
@@ -1685,7 +1756,7 @@ check_nonexistent_service_auto_start (BusContext     *context,
                       dbus_message_get_sender (message) : "(none)");
           goto out;
         }
-      
+
       if (dbus_message_is_error (message,
                                  DBUS_ERROR_NO_MEMORY))
         {
@@ -1710,11 +1781,11 @@ check_nonexistent_service_auto_start (BusContext     *context,
     }
 
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -1728,16 +1799,16 @@ check_base_service_activated (BusContext     *context,
   dbus_bool_t retval;
   DBusError error;
   const char *base_service, *base_service_from_bus, *old_owner;
-  
+
   retval = FALSE;
-  
+
   dbus_error_init (&error);
   base_service = NULL;
   old_owner = NULL;
   base_service_from_bus = NULL;
 
   message = initial_message;
-  dbus_message_ref (message);  
+  dbus_message_ref (message);
 
   if (dbus_message_is_signal (message,
                               DBUS_INTERFACE_DBUS,
@@ -1777,7 +1848,7 @@ check_base_service_activated (BusContext     *context,
                       base_service);
           goto out;
         }
-         
+
       if (strcmp (base_service, base_service_from_bus) != 0)
         {
           _dbus_warn ("Expected base service activation, got \"%s\" instead with owner \"%s\"\n",
@@ -1791,14 +1862,14 @@ check_base_service_activated (BusContext     *context,
                       old_owner);
           goto out;
         }
-     
+
       socd.expected_kind = SERVICE_CREATED;
       socd.expected_service_name = base_service;
       socd.failed = FALSE;
       socd.skip_connection = connection;
       bus_test_clients_foreach (check_service_owner_changed_foreach,
                                 &socd);
-      
+
       if (socd.failed)
         goto out;
     }
@@ -1813,7 +1884,7 @@ check_base_service_activated (BusContext     *context,
     *base_service_p = base_service;
 
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
@@ -1833,9 +1904,9 @@ check_service_activated (BusContext     *context,
   dbus_bool_t retval;
   DBusError error;
   dbus_uint32_t activation_result;
-  
+
   retval = FALSE;
-  
+
   dbus_error_init (&error);
 
   message = initial_message;
@@ -1902,15 +1973,15 @@ check_service_activated (BusContext     *context,
       socd.expected_service_name = service_name;
       bus_test_clients_foreach (check_service_owner_changed_foreach,
                                 &socd);
-          
+
       if (socd.failed)
         goto out;
-          
+
       dbus_message_unref (message);
       service_name = NULL;
       old_owner = NULL;
       base_service_from_bus = NULL;
-      
+
       message = pop_message_waiting_for_memory (connection);
       if (message == NULL)
         {
@@ -1922,10 +1993,10 @@ check_service_activated (BusContext     *context,
   else
     {
       warn_unexpected (connection, message, "NameOwnerChanged for the activated name");
-      
+
       goto out;
     }
-  
+
   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
     {
       warn_unexpected (connection, message, "reply to StartServiceByName");
@@ -1963,7 +2034,7 @@ check_service_activated (BusContext     *context,
 
   dbus_message_unref (message);
   message = NULL;
-      
+
   if (!check_no_leftovers (context))
     {
       _dbus_warn ("Messages were left over after verifying existent activation results\n");
@@ -1971,12 +2042,12 @@ check_service_activated (BusContext     *context,
     }
 
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
   dbus_error_free (&error);
-  
+
   return retval;
 }
 
@@ -1990,9 +2061,9 @@ check_service_auto_activated (BusContext     *context,
   DBusMessage *message;
   dbus_bool_t retval;
   DBusError error;
-  
+
   retval = FALSE;
-  
+
   dbus_error_init (&error);
 
   message = initial_message;
@@ -2004,7 +2075,7 @@ check_service_auto_activated (BusContext     *context,
     {
       const char *service_name;
       CheckServiceOwnerChangedData socd;
-      
+
     reget_service_name_arg:
       if (!dbus_message_get_args (message, &error,
                                   DBUS_TYPE_STRING, &service_name,
@@ -2025,28 +2096,28 @@ check_service_auto_activated (BusContext     *context,
               goto out;
             }
         }
-      
+
       if (strcmp (service_name, activated_name) != 0)
         {
           _dbus_warn ("Expected to see service %s created, saw %s instead\n",
                       activated_name, service_name);
           goto out;
         }
-      
+
       socd.expected_kind = SERVICE_CREATED;
       socd.expected_service_name = service_name;
       socd.failed = FALSE;
-      socd.skip_connection = connection; 
+      socd.skip_connection = connection;
       bus_test_clients_foreach (check_service_owner_changed_foreach,
                                 &socd);
-      
+
       if (socd.failed)
         goto out;
-      
+
       /* Note that this differs from regular activation in that we don't get a
        * reply to ActivateService here.
        */
-      
+
       dbus_message_unref (message);
       message = NULL;
       service_name = NULL;
@@ -2054,16 +2125,16 @@ check_service_auto_activated (BusContext     *context,
   else
     {
       warn_unexpected (connection, message, "NameOwnerChanged for the activated name");
-      
+
       goto out;
     }
-  
+
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -2077,7 +2148,7 @@ check_service_deactivated (BusContext     *context,
   CheckServiceOwnerChangedData socd;
 
   retval = FALSE;
-  
+
   /* Now we are expecting ServiceOwnerChanged (deletion) messages for the base
    * service and the activated_name.  The base service
    * notification is required to come last.
@@ -2087,11 +2158,11 @@ check_service_deactivated (BusContext     *context,
   socd.failed = FALSE;
   socd.skip_connection = NULL;
   bus_test_clients_foreach (check_service_owner_changed_foreach,
-                            &socd);      
+                            &socd);
 
   if (socd.failed)
     goto out;
-      
+
   socd.expected_kind = SERVICE_DELETED;
   socd.expected_service_name = base_service;
   socd.failed = FALSE;
@@ -2103,7 +2174,7 @@ check_service_deactivated (BusContext     *context,
     goto out;
 
   retval = TRUE;
-  
+
  out:
   return retval;
 }
@@ -2118,27 +2189,27 @@ check_send_exit_to_service (BusContext     *context,
   DBusMessage *message;
   dbus_uint32_t serial;
   dbus_bool_t retval;
-  
+
   _dbus_verbose ("Sending exit message to the test service\n");
 
   retval = FALSE;
-  
+
   /* Kill off the test service by sending it a quit message */
   message = dbus_message_new_method_call (service_name,
                                           "/org/freedesktop/TestSuite",
                                           "org.freedesktop.TestSuite",
                                           "Exit");
-      
+
   if (message == NULL)
     {
       /* Do this again; we still need the service to exit... */
       if (!check_send_exit_to_service (context, connection,
                                        service_name, base_service))
         goto out;
-      
+
       return TRUE;
     }
-      
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -2147,7 +2218,7 @@ check_send_exit_to_service (BusContext     *context,
       if (!check_send_exit_to_service (context, connection,
                                        service_name, base_service))
         goto out;
-      
+
       return TRUE;
     }
 
@@ -2169,12 +2240,12 @@ check_send_exit_to_service (BusContext     *context,
       dbus_connection_return_message (connection, message);
       message = NULL;
     }
-          
+
   if (!got_error)
     {
       /* If no error, wait for the test service to exit */
       block_connection_until_message_from_bus (context, connection, "test service to exit");
-              
+
       bus_test_run_everything (context);
     }
 
@@ -2189,7 +2260,7 @@ check_send_exit_to_service (BusContext     *context,
                            "error with the correct reply serial");
           goto out;
         }
-      
+
       if (!dbus_message_is_error (message,
                                   DBUS_ERROR_NO_MEMORY))
         {
@@ -2217,7 +2288,7 @@ check_send_exit_to_service (BusContext     *context,
        * stuff.
        */
       message = pop_message_waiting_for_memory (connection);
-          
+
       if (message == NULL)
         {
           warn_unexpected (connection, NULL,
@@ -2238,10 +2309,10 @@ check_send_exit_to_service (BusContext     *context,
                            "error with the correct reply serial");
           goto out;
         }
-          
+
       _dbus_verbose ("Got error %s after test service exited\n",
                      dbus_message_get_error_name (message));
-      
+
       if (!check_no_leftovers (context))
         {
           _dbus_warn ("Messages were left over after %s\n",
@@ -2249,13 +2320,13 @@ check_send_exit_to_service (BusContext     *context,
           goto out;
         }
     }
-  
+
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -2270,9 +2341,9 @@ check_got_error (BusContext     *context,
   va_list ap;
   dbus_bool_t error_found;
   const char *error_name;
-  
+
   retval = FALSE;
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -2311,20 +2382,20 @@ check_got_error (BusContext     *context,
     }
 
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
-          
+
 typedef enum
-{ 
+{
   GOT_SERVICE_CREATED,
   GOT_SERVICE_DELETED,
   GOT_ERROR,
-  GOT_SOMETHING_ELSE 
+  GOT_SOMETHING_ELSE
 } GotServiceInfo;
 
 static GotServiceInfo
@@ -2398,7 +2469,7 @@ check_existent_service_no_auto_start (BusContext     *context,
   dbus_uint32_t flags;
 
   base_service_message = NULL;
-  
+
   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                           DBUS_PATH_DBUS,
                                           DBUS_INTERFACE_DBUS,
@@ -2408,7 +2479,7 @@ check_existent_service_no_auto_start (BusContext     *context,
     return TRUE;
 
   dbus_message_set_auto_start (message, FALSE);
-  
+
   flags = 0;
   if (!dbus_message_append_args (message,
                                  DBUS_TYPE_STRING, &existent,
@@ -2418,7 +2489,7 @@ check_existent_service_no_auto_start (BusContext     *context,
       dbus_message_unref (message);
       return TRUE;
     }
-  
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -2439,12 +2510,12 @@ check_existent_service_no_auto_start (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
       return TRUE;
     }
-  
+
   retval = FALSE;
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -2465,7 +2536,7 @@ check_existent_service_no_auto_start (BusContext     *context,
                       dbus_message_get_sender (message) : "(none)");
           goto out;
         }
-      
+
       if (dbus_message_is_error (message,
                                  DBUS_ERROR_NO_MEMORY))
         {
@@ -2490,7 +2561,7 @@ check_existent_service_no_auto_start (BusContext     *context,
   else
     {
       GotServiceInfo message_kind;
-      
+
       if (!check_base_service_activated (context, connection,
                                          message, &base_service))
         goto out;
@@ -2500,7 +2571,7 @@ check_existent_service_no_auto_start (BusContext     *context,
 
       /* We may need to block here for the test service to exit or finish up */
       block_connection_until_message_from_bus (context, connection, "test service to exit or finish up");
-      
+
       message = dbus_connection_borrow_message (connection);
       if (message == NULL)
         {
@@ -2543,7 +2614,7 @@ check_existent_service_no_auto_start (BusContext     *context,
             socd.expected_service_name = base_service;
             socd.failed = FALSE;
             socd.skip_connection = NULL;
-            
+
             bus_test_clients_foreach (check_service_owner_changed_foreach,
                                       &socd);
 
@@ -2556,10 +2627,10 @@ check_existent_service_no_auto_start (BusContext     *context,
             if (message_kind != GOT_ERROR)
               {
                 block_connection_until_message_from_bus (context, connection, "error about service exiting");
-               
+
                 /* and process everything again */
                 bus_test_run_everything (context);
-              
+
                 if (!check_got_error (context, connection,
                                       DBUS_ERROR_SPAWN_CHILD_EXITED,
                                      DBUS_ERROR_NO_MEMORY,
@@ -2577,11 +2648,11 @@ check_existent_service_no_auto_start (BusContext     *context,
                           "should have been a NameOwnerChanged (creation)\n");
               goto out;
             }
-          
+
           if (!check_service_activated (context, connection, EXISTENT_SERVICE_NAME,
                                         base_service, message))
             goto out;
-          
+
           dbus_message_unref (message);
           message = NULL;
 
@@ -2600,14 +2671,14 @@ check_existent_service_no_auto_start (BusContext     *context,
     }
 
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
 
   if (base_service_message)
     dbus_message_unref (base_service_message);
-  
+
   return retval;
 }
 
@@ -2624,7 +2695,7 @@ check_segfault_service_no_auto_start (BusContext     *context,
   dbus_bool_t retval;
   const char *segv_service;
   dbus_uint32_t flags;
-  
+
   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                           DBUS_PATH_DBUS,
                                           DBUS_INTERFACE_DBUS,
@@ -2634,7 +2705,7 @@ check_segfault_service_no_auto_start (BusContext     *context,
     return TRUE;
 
   dbus_message_set_auto_start (message, FALSE);
-  
+
   segv_service = "org.freedesktop.DBus.TestSuiteSegfaultService";
   flags = 0;
   if (!dbus_message_append_args (message,
@@ -2645,7 +2716,7 @@ check_segfault_service_no_auto_start (BusContext     *context,
       dbus_message_unref (message);
       return TRUE;
     }
-  
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -2661,12 +2732,12 @@ check_segfault_service_no_auto_start (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
       return TRUE;
     }
-  
+
   retval = FALSE;
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -2686,13 +2757,21 @@ check_segfault_service_no_auto_start (BusContext     *context,
                       dbus_message_get_sender (message) : "(none)");
           goto out;
         }
-      
+
       if (dbus_message_is_error (message,
                                  DBUS_ERROR_NO_MEMORY))
         {
           ; /* good, this is a valid response */
         }
       else if (dbus_message_is_error (message,
+                                      DBUS_ERROR_FAILED))
+        {
+          const char *servicehelper;
+          servicehelper = bus_context_get_servicehelper (context);
+          /* make sure this only happens with the launch helper */
+          _dbus_assert (servicehelper != NULL);
+        }
+      else if (dbus_message_is_error (message,
                                       DBUS_ERROR_SPAWN_CHILD_SIGNALED))
         {
           ; /* good, this is expected also */
@@ -2711,11 +2790,11 @@ check_segfault_service_no_auto_start (BusContext     *context,
     }
 
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -2735,10 +2814,10 @@ check_segfault_service_auto_start (BusContext     *context,
                                           "/org/freedesktop/TestSuite",
                                           "org.freedesktop.TestSuite",
                                           "Echo");
-  
+
   if (message == NULL)
     return TRUE;
-  
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -2754,12 +2833,12 @@ check_segfault_service_auto_start (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
       return TRUE;
     }
-  
+
   retval = FALSE;
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -2779,7 +2858,7 @@ check_segfault_service_auto_start (BusContext     *context,
                       dbus_message_get_sender (message) : "(none)");
           goto out;
         }
-      
+
       if (dbus_message_is_error (message,
                                  DBUS_ERROR_NO_MEMORY))
         {
@@ -2804,11 +2883,11 @@ check_segfault_service_auto_start (BusContext     *context,
     }
 
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 #endif
@@ -2831,7 +2910,7 @@ check_existent_hello_from_self (BusContext     *context,
                                           "/org/freedesktop/TestSuite",
                                           "org.freedesktop.TestSuite",
                                           "RunHelloFromSelf");
-  
+
   if (message == NULL)
     return TRUE;
 
@@ -2859,7 +2938,7 @@ check_existent_hello_from_self (BusContext     *context,
    * doesn't send a reply due to OOM.
    */
   block_connection_until_message_from_bus (context, connection, "reply from running hello from self");
-      
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -2876,7 +2955,7 @@ check_existent_hello_from_self (BusContext     *context,
 
   dbus_message_unref (message);
   message = NULL;
-      
+
   return TRUE;
 }
 
@@ -2893,7 +2972,7 @@ check_existent_ping (BusContext     *context,
                                           "/org/freedesktop/TestSuite",
                                           "org.freedesktop.DBus.Peer",
                                           "Ping");
-  
+
   if (message == NULL)
     return TRUE;
 
@@ -2912,7 +2991,7 @@ check_existent_ping (BusContext     *context,
    * doesn't send a reply due to OOM.
    */
   block_connection_until_message_from_bus (context, connection, "reply from running Ping");
-      
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -2936,7 +3015,7 @@ check_existent_ping (BusContext     *context,
 
   dbus_message_unref (message);
   message = NULL;
-      
+
   return TRUE;
 }
 
@@ -2950,12 +3029,12 @@ check_existent_get_machine_id (BusContext     *context,
   DBusMessage *message;
   dbus_uint32_t serial;
   const char *machine_id;
-  
+
   message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME,
                                           "/org/freedesktop/TestSuite",
                                           "org.freedesktop.DBus.Peer",
                                           "GetMachineId");
-  
+
   if (message == NULL)
     return TRUE;
 
@@ -2974,7 +3053,7 @@ check_existent_get_machine_id (BusContext     *context,
    * doesn't send a reply due to OOM.
    */
   block_connection_until_message_from_bus (context, connection, "reply from running GetMachineId");
-      
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -3010,14 +3089,14 @@ check_existent_get_machine_id (BusContext     *context,
       dbus_message_unref (message);
       return FALSE;
     }
-  
+
   /* We can't check that the machine id is correct because during make check it is
    * just made up for each process separately
    */
-  
+
   dbus_message_unref (message);
   message = NULL;
-      
+
   return TRUE;
 }
 
@@ -3041,7 +3120,7 @@ check_existent_service_auto_start (BusContext     *context,
                                           "/org/freedesktop/TestSuite",
                                           "org.freedesktop.TestSuite",
                                           "Echo");
-  
+
   if (message == NULL)
     return TRUE;
 
@@ -3073,12 +3152,12 @@ check_existent_service_auto_start (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
       return TRUE;
     }
 
   retval = FALSE;
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -3123,7 +3202,7 @@ check_existent_service_auto_start (BusContext     *context,
       dbus_connection_return_message (connection, message);
       message = NULL;
 
-      switch (message_kind) 
+      switch (message_kind)
         {
         case GOT_SERVICE_CREATED:
           message = pop_message_waiting_for_memory (connection);
@@ -3133,12 +3212,12 @@ check_existent_service_auto_start (BusContext     *context,
                           "should have been a NameOwnerChanged (creation)\n");
               goto out;
             }
-            
+
           /* Check that ServiceOwnerChanged (creation) was correctly received */
           if (!check_service_auto_activated (context, connection, EXISTENT_SERVICE_NAME,
                                              base_service, message))
             goto out;
-          
+
           dbus_message_unref (message);
           message = NULL;
 
@@ -3150,7 +3229,7 @@ check_existent_service_auto_start (BusContext     *context,
              * failed to register under EXISTENT_SERVICE_NAME
              */
             CheckServiceOwnerChangedData socd;
-          
+
             socd.expected_kind = SERVICE_DELETED;
             socd.expected_service_name = base_service;
             socd.failed = FALSE;
@@ -3164,61 +3243,460 @@ check_existent_service_auto_start (BusContext     *context,
             break;
           }
 
-        case GOT_ERROR:
-        case GOT_SOMETHING_ELSE:
-          _dbus_warn ("Unexpected message after auto activation\n");
+        case GOT_ERROR:
+        case GOT_SOMETHING_ELSE:
+          _dbus_warn ("Unexpected message after auto activation\n");
+          goto out;
+        }
+    }
+
+  /* OK, now we've dealt with ServiceOwnerChanged signals, now should
+   * come the method reply (or error) from the initial method call
+   */
+
+  /* Note: if this test is run in OOM mode, it will block when the bus
+   * doesn't send a reply due to OOM.
+   */
+  block_connection_until_message_from_bus (context, connection, "reply from echo message after auto-activation");
+
+  message = pop_message_waiting_for_memory (connection);
+  if (message == NULL)
+    {
+      _dbus_warn ("Failed to pop message! Should have been reply from echo message\n");
+      goto out;
+    }
+
+  if (dbus_message_get_reply_serial (message) != serial)
+    {
+      _dbus_warn ("Wrong reply serial\n");
+      goto out;
+    }
+
+  dbus_message_unref (message);
+  message = NULL;
+
+  if (!check_existent_ping (context, connection))
+    goto out;
+
+  if (!check_existent_get_machine_id (context, connection))
+    goto out;
+
+  if (!check_existent_hello_from_self (context, connection))
+    goto out;
+
+  if (!check_send_exit_to_service (context, connection,
+                                   EXISTENT_SERVICE_NAME,
+                                   base_service))
+    goto out;
+
+  retval = TRUE;
+
+ out:
+  if (message)
+    dbus_message_unref (message);
+
+  if (base_service_message)
+    dbus_message_unref (base_service_message);
+
+  return retval;
+}
+
+#define SERVICE_FILE_MISSING_NAME "org.freedesktop.DBus.TestSuiteEchoServiceDotServiceFileDoesNotExist"
+
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
+check_launch_service_file_missing (BusContext     *context,
+                                   DBusConnection *connection)
+{
+  DBusMessage *message;
+  dbus_uint32_t serial;
+  dbus_bool_t retval;
+
+  message = dbus_message_new_method_call (SERVICE_FILE_MISSING_NAME,
+                                          "/org/freedesktop/TestSuite",
+                                          "org.freedesktop.TestSuite",
+                                          "Echo");
+
+  if (message == NULL)
+    return TRUE;
+
+  if (!dbus_connection_send (connection, message, &serial))
+    {
+      dbus_message_unref (message);
+      return TRUE;
+    }
+
+  dbus_message_unref (message);
+  message = NULL;
+
+  bus_test_run_everything (context);
+  block_connection_until_message_from_bus (context, connection, "reply to service file missing should fail to auto-start");
+  bus_test_run_everything (context);
+
+  if (!dbus_connection_get_is_connected (connection))
+    {
+      _dbus_verbose ("connection was disconnected\n");
+      return TRUE;
+    }
+
+  retval = FALSE;
+
+  message = pop_message_waiting_for_memory (connection);
+  if (message == NULL)
+    {
+      _dbus_warn ("Did not receive a reply to %s %d on %p\n",
+                  "Echo message (auto activation)", serial, connection);
+      goto out;
+    }
+
+  verbose_message_received (connection, message);
+
+  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
+    {
+      if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
+        {
+          _dbus_warn ("Message has wrong sender %s\n",
+                      dbus_message_get_sender (message) ?
+                      dbus_message_get_sender (message) : "(none)");
+          goto out;
+        }
+
+      if (dbus_message_is_error (message,
+                                 DBUS_ERROR_NO_MEMORY))
+        {
+          ; /* good, this is a valid response */
+        }
+      else if (dbus_message_is_error (message,
+                                      DBUS_ERROR_SERVICE_UNKNOWN))
+        {
+          _dbus_verbose("got service unknown\n");
+          ; /* good, this is expected (only valid when using launch helper) */
+        }
+      else
+        {
+          warn_unexpected (connection, message, "not this error");
+
+          goto out;
+        }
+    }
+  else
+    {
+      _dbus_warn ("Did not expect to successfully auto-start missing service\n");
+      goto out;
+    }
+
+  retval = TRUE;
+
+ out:
+  if (message)
+    dbus_message_unref (message);
+
+  return retval;
+}
+
+#define SERVICE_USER_MISSING_NAME "org.freedesktop.DBus.TestSuiteNoUser"
+
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
+check_launch_service_user_missing (BusContext     *context,
+                                   DBusConnection *connection)
+{
+  DBusMessage *message;
+  dbus_uint32_t serial;
+  dbus_bool_t retval;
+
+  message = dbus_message_new_method_call (SERVICE_USER_MISSING_NAME,
+                                          "/org/freedesktop/TestSuite",
+                                          "org.freedesktop.TestSuite",
+                                          "Echo");
+
+  if (message == NULL)
+    return TRUE;
+
+  if (!dbus_connection_send (connection, message, &serial))
+    {
+      dbus_message_unref (message);
+      return TRUE;
+    }
+
+  dbus_message_unref (message);
+  message = NULL;
+
+  bus_test_run_everything (context);
+  block_connection_until_message_from_bus (context, connection,
+                                          "reply to service which should fail to auto-start (missing User)");
+  bus_test_run_everything (context);
+
+  if (!dbus_connection_get_is_connected (connection))
+    {
+      _dbus_warn ("connection was disconnected\n");
+      return TRUE;
+    }
+
+  retval = FALSE;
+
+  message = pop_message_waiting_for_memory (connection);
+  if (message == NULL)
+    {
+      _dbus_warn ("Did not receive a reply to %s %d on %p\n",
+                  "Echo message (auto activation)", serial, connection);
+      goto out;
+    }
+
+  verbose_message_received (connection, message);
+
+  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
+    {
+      if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
+        {
+          _dbus_warn ("Message has wrong sender %s\n",
+                      dbus_message_get_sender (message) ?
+                      dbus_message_get_sender (message) : "(none)");
+          goto out;
+        }
+
+      if (dbus_message_is_error (message,
+                                 DBUS_ERROR_NO_MEMORY))
+        {
+          ; /* good, this is a valid response */
+        }
+      else if (dbus_message_is_error (message,
+                                      DBUS_ERROR_SPAWN_FILE_INVALID))
+        {
+          _dbus_verbose("got service file invalid\n");
+          ; /* good, this is expected (only valid when using launch helper) */
+        }
+      else
+        {
+          warn_unexpected (connection, message, "not this error");
+
+          goto out;
+        }
+    }
+  else
+    {
+      _dbus_warn ("Did not expect to successfully auto-start missing service\n");
+      goto out;
+    }
+
+  retval = TRUE;
+
+ out:
+  if (message)
+    dbus_message_unref (message);
+
+  return retval;
+}
+
+#define SERVICE_EXEC_MISSING_NAME "org.freedesktop.DBus.TestSuiteNoExec"
+
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
+check_launch_service_exec_missing (BusContext     *context,
+                                   DBusConnection *connection)
+{
+  DBusMessage *message;
+  dbus_uint32_t serial;
+  dbus_bool_t retval;
+
+  message = dbus_message_new_method_call (SERVICE_EXEC_MISSING_NAME,
+                                          "/org/freedesktop/TestSuite",
+                                          "org.freedesktop.TestSuite",
+                                          "Echo");
+
+  if (message == NULL)
+    return TRUE;
+
+  if (!dbus_connection_send (connection, message, &serial))
+    {
+      dbus_message_unref (message);
+      return TRUE;
+    }
+
+  dbus_message_unref (message);
+  message = NULL;
+
+  bus_test_run_everything (context);
+  block_connection_until_message_from_bus (context, connection,
+                                          "reply to service which should fail to auto-start (missing Exec)");
+  bus_test_run_everything (context);
+
+  if (!dbus_connection_get_is_connected (connection))
+    {
+      _dbus_warn ("connection was disconnected\n");
+      return TRUE;
+    }
+
+  retval = FALSE;
+
+  message = pop_message_waiting_for_memory (connection);
+  if (message == NULL)
+    {
+      _dbus_warn ("Did not receive a reply to %s %d on %p\n",
+                  "Echo message (auto activation)", serial, connection);
+      goto out;
+    }
+
+  verbose_message_received (connection, message);
+
+  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
+    {
+      if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
+        {
+          _dbus_warn ("Message has wrong sender %s\n",
+                      dbus_message_get_sender (message) ?
+                      dbus_message_get_sender (message) : "(none)");
+          goto out;
+        }
+
+      if (dbus_message_is_error (message,
+                                 DBUS_ERROR_NO_MEMORY))
+        {
+          ; /* good, this is a valid response */
+        }
+      else if (dbus_message_is_error (message,
+                                      DBUS_ERROR_SERVICE_UNKNOWN))
+        {
+          _dbus_verbose("could not activate as invalid service file was not added\n");
+          ; /* good, this is expected as we shouldn't have been added to
+             * the activation list with a missing Exec key */
+        }
+      else if (dbus_message_is_error (message,
+                                      DBUS_ERROR_SPAWN_FILE_INVALID))
+        {
+          _dbus_verbose("got service file invalid\n");
+          ; /* good, this is allowed, and is the message passed back from the
+             * launch helper */
+        }
+      else
+        {
+          warn_unexpected (connection, message, "not this error");
+
+          goto out;
+        }
+    }
+  else
+    {
+      _dbus_warn ("Did not expect to successfully auto-start missing service\n");
+      goto out;
+    }
+
+  retval = TRUE;
+
+ out:
+  if (message)
+    dbus_message_unref (message);
+
+  return retval;
+}
+
+#define SERVICE_SERVICE_MISSING_NAME "org.freedesktop.DBus.TestSuiteNoService"
+
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
+check_launch_service_service_missing (BusContext     *context,
+                                      DBusConnection *connection)
+{
+  DBusMessage *message;
+  dbus_uint32_t serial;
+  dbus_bool_t retval;
+
+  message = dbus_message_new_method_call (SERVICE_SERVICE_MISSING_NAME,
+                                          "/org/freedesktop/TestSuite",
+                                          "org.freedesktop.TestSuite",
+                                          "Echo");
+
+  if (message == NULL)
+    return TRUE;
+
+  if (!dbus_connection_send (connection, message, &serial))
+    {
+      dbus_message_unref (message);
+      return TRUE;
+    }
+
+  dbus_message_unref (message);
+  message = NULL;
+
+  bus_test_run_everything (context);
+  block_connection_until_message_from_bus (context, connection,
+                                          "reply to service which should fail to auto-start (missing Service)");
+  bus_test_run_everything (context);
+
+  if (!dbus_connection_get_is_connected (connection))
+    {
+      _dbus_warn ("connection was disconnected\n");
+      return TRUE;
+    }
+
+  retval = FALSE;
+
+  message = pop_message_waiting_for_memory (connection);
+  if (message == NULL)
+    {
+      _dbus_warn ("Did not receive a reply to %s %d on %p\n",
+                  "Echo message (auto activation)", serial, connection);
+      goto out;
+    }
+
+  verbose_message_received (connection, message);
+
+  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
+    {
+      if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
+        {
+          _dbus_warn ("Message has wrong sender %s\n",
+                      dbus_message_get_sender (message) ?
+                      dbus_message_get_sender (message) : "(none)");
+          goto out;
+        }
+
+      if (dbus_message_is_error (message,
+                                 DBUS_ERROR_NO_MEMORY))
+        {
+          ; /* good, this is a valid response */
+        }
+      else if (dbus_message_is_error (message,
+                                      DBUS_ERROR_SERVICE_UNKNOWN))
+        {
+          _dbus_verbose("could not activate as invalid service file was not added\n");
+          ; /* good, this is expected as we shouldn't have been added to
+             * the activation list with a missing Exec key */
+        }
+      else if (dbus_message_is_error (message,
+                                      DBUS_ERROR_SPAWN_FILE_INVALID))
+        {
+          _dbus_verbose("got service file invalid\n");
+          ; /* good, this is allowed, and is the message passed back from the
+             * launch helper */
+        }
+      else
+        {
+          warn_unexpected (connection, message, "not this error");
+
           goto out;
         }
     }
-
-  /* OK, now we've dealt with ServiceOwnerChanged signals, now should
-   * come the method reply (or error) from the initial method call
-   */
-
-  /* Note: if this test is run in OOM mode, it will block when the bus
-   * doesn't send a reply due to OOM.
-   */
-  block_connection_until_message_from_bus (context, connection, "reply from echo message after auto-activation");
-      
-  message = pop_message_waiting_for_memory (connection);
-  if (message == NULL)
-    {
-      _dbus_warn ("Failed to pop message! Should have been reply from echo message\n");
-      goto out;
-    }
-
-  if (dbus_message_get_reply_serial (message) != serial)
+  else
     {
-      _dbus_warn ("Wrong reply serial\n");
+      _dbus_warn ("Did not expect to successfully auto-start missing service\n");
       goto out;
     }
 
-  dbus_message_unref (message);
-  message = NULL;
-
-  if (!check_existent_ping (context, connection))
-    goto out;
-
-  if (!check_existent_get_machine_id (context, connection))
-    goto out;
-  
-  if (!check_existent_hello_from_self (context, connection))
-    goto out;
-
-  if (!check_send_exit_to_service (context, connection,
-                                   EXISTENT_SERVICE_NAME,
-                                   base_service))
-    goto out;
-  
   retval = TRUE;
 
  out:
   if (message)
     dbus_message_unref (message);
 
-  if (base_service_message)
-    dbus_message_unref (base_service_message);
-
   return retval;
 }
 
@@ -3239,10 +3717,10 @@ check_shell_fail_service_auto_start (BusContext     *context,
                                           "/org/freedesktop/TestSuite",
                                           "org.freedesktop.TestSuite",
                                           "Echo");
-  
+
   if (message == NULL)
     return TRUE;
-  
+
   if (!dbus_connection_send (connection, message, &serial))
     {
       dbus_message_unref (message);
@@ -3258,12 +3736,12 @@ check_shell_fail_service_auto_start (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
       return TRUE;
     }
-  
+
   retval = FALSE;
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -3283,7 +3761,7 @@ check_shell_fail_service_auto_start (BusContext     *context,
                       dbus_message_get_sender (message) : "(none)");
           goto out;
         }
-      
+
       if (dbus_message_is_error (message,
                                  DBUS_ERROR_NO_MEMORY))
         {
@@ -3309,11 +3787,11 @@ check_shell_fail_service_auto_start (BusContext     *context,
     }
 
   retval = TRUE;
-  
+
  out:
   if (message)
     dbus_message_unref (message);
-  
+
   return retval;
 }
 
@@ -3339,7 +3817,7 @@ check_shell_service_success_auto_start (BusContext     *context,
                                           "/org/freedesktop/TestSuite",
                                           "org.freedesktop.TestSuite",
                                           "Echo");
-  
+
   if (message == NULL)
     return TRUE;
 
@@ -3362,12 +3840,12 @@ check_shell_service_success_auto_start (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
       return TRUE;
     }
 
   retval = FALSE;
-  
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -3412,7 +3890,7 @@ check_shell_service_success_auto_start (BusContext     *context,
       dbus_connection_return_message (connection, message);
       message = NULL;
 
-      switch (message_kind) 
+      switch (message_kind)
         {
         case GOT_SERVICE_CREATED:
           message = pop_message_waiting_for_memory (connection);
@@ -3422,12 +3900,12 @@ check_shell_service_success_auto_start (BusContext     *context,
                           "should have been a NameOwnerChanged (creation)\n");
               goto out;
             }
-            
+
           /* Check that ServiceOwnerChanged (creation) was correctly received */
           if (!check_service_auto_activated (context, connection, SHELL_SUCCESS_SERVICE_NAME,
                                              base_service, message))
             goto out;
-          
+
           dbus_message_unref (message);
           message = NULL;
 
@@ -3439,7 +3917,7 @@ check_shell_service_success_auto_start (BusContext     *context,
              * failed to register under SHELL_SUCCESS_SERVICE_NAME
              */
             CheckServiceOwnerChangedData socd;
-          
+
             socd.expected_kind = SERVICE_DELETED;
             socd.expected_service_name = base_service;
             socd.failed = FALSE;
@@ -3468,7 +3946,7 @@ check_shell_service_success_auto_start (BusContext     *context,
    * doesn't send a reply due to OOM.
    */
   block_connection_until_message_from_bus (context, connection, "reply from echo message after auto-activation");
-      
+
   message = pop_message_waiting_for_memory (connection);
   if (message == NULL)
     {
@@ -3483,7 +3961,7 @@ check_shell_service_success_auto_start (BusContext     *context,
     }
 
   if (!dbus_message_get_args (message, NULL,
-                                       DBUS_TYPE_STRING, &argv[0], 
+                                       DBUS_TYPE_STRING, &argv[0],
                                        DBUS_TYPE_STRING, &argv[1],
                                        DBUS_TYPE_STRING, &argv[2],
                                        DBUS_TYPE_STRING, &argv[3],
@@ -3496,59 +3974,59 @@ check_shell_service_success_auto_start (BusContext     *context,
       goto out;
     }
 
-   /* don't worry about arg[0] as it may be different 
+   /* don't worry about arg[0] as it may be different
       depending on the path to the tests
    */
   if (strcmp("-test", argv[1]) != 0)
     {
-      _dbus_warn ("Unexpected argv[1] in shell success service test (expected: %s, got: %s)\n", 
+      _dbus_warn ("Unexpected argv[1] in shell success service test (expected: %s, got: %s)\n",
                   "-test", argv[1]);
       goto out;
-    } 
+    }
 
   if (strcmp("that", argv[2]) != 0)
     {
-      _dbus_warn ("Unexpected argv[2] in shell success service test (expected: %s, got: %s)\n", 
+      _dbus_warn ("Unexpected argv[2] in shell success service test (expected: %s, got: %s)\n",
                    "that", argv[2]);
       goto out;
-    } 
+    }
 
   if (strcmp("we get", argv[3]) != 0)
     {
-      _dbus_warn ("Unexpected argv[3] in shell success service test (expected: %s, got: %s)\n", 
+      _dbus_warn ("Unexpected argv[3] in shell success service test (expected: %s, got: %s)\n",
                    "we get", argv[3]);
       goto out;
-    } 
-   
+    }
+
   if (strcmp("back", argv[4]) != 0)
     {
-      _dbus_warn ("Unexpected argv[4] in shell success service test (expected: %s, got: %s)\n", 
+      _dbus_warn ("Unexpected argv[4] in shell success service test (expected: %s, got: %s)\n",
                    "back", argv[4]);
       goto out;
-    } 
+    }
 
   if (strcmp("--what", argv[5]) != 0)
     {
-      _dbus_warn ("Unexpected argv[5] in shell success service test (expected: %s, got: %s)\n", 
+      _dbus_warn ("Unexpected argv[5] in shell success service test (expected: %s, got: %s)\n",
                    "--what", argv[5]);
       goto out;
-    } 
+    }
 
   if (strcmp("we put in", argv[6]) != 0)
     {
-      _dbus_warn ("Unexpected argv[6] in shell success service test (expected: %s, got: %s)\n", 
+      _dbus_warn ("Unexpected argv[6] in shell success service test (expected: %s, got: %s)\n",
                    "we put in", argv[6]);
       goto out;
-    } 
+    }
 
   dbus_message_unref (message);
   message = NULL;
-      
+
   if (!check_send_exit_to_service (context, connection,
                                    SHELL_SUCCESS_SERVICE_NAME,
                                    base_service))
     goto out;
-  
+
   retval = TRUE;
 
  out:
@@ -3574,7 +4052,7 @@ check_oom_check1_func (void *data)
 
   if (! (* d->func) (d->context))
     return FALSE;
-  
+
   if (!check_no_leftovers (d->context))
     {
       _dbus_warn ("Messages were left over, should be covered by test suite\n");
@@ -3642,7 +4120,7 @@ check_get_services (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
 
       dbus_connection_unref (connection);
 
@@ -3714,15 +4192,15 @@ check_get_services (BusContext     *context,
          *len = l;
        }
     }
-  
+
   if (!check_no_leftovers (context))
     goto out;
-  
+
   retval = TRUE;
-  
+
  out:
   dbus_error_free (&error);
-  
+
   if (message)
     dbus_message_unref (message);
 
@@ -3756,6 +4234,7 @@ check_list_services (BusContext     *context,
   if (!_dbus_string_array_contains ((const char **)services, existent))
     {
       _dbus_warn ("Did not get the expected %s from ListActivatableNames\n", existent);
+      dbus_free_string_array (services);
       return FALSE;
     }
 
@@ -3803,7 +4282,7 @@ check_list_services (BusContext     *context,
 
   if (!dbus_connection_get_is_connected (connection))
     {
-      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
+      _dbus_verbose ("connection was disconnected\n");
       return TRUE;
     }
 
@@ -3894,7 +4373,7 @@ check_list_services (BusContext     *context,
                          "should have been a NameOwnerChanged (creation)\n");
              goto out;
            }
-         
+
          if (!check_service_activated (context, connection, EXISTENT_SERVICE_NAME,
                                        base_service, message))
            goto out;
@@ -3911,7 +4390,7 @@ check_list_services (BusContext     *context,
          break;
        }
     }
-  
+
   if (!check_get_services (context, connection, "ListNames", &services, &len))
     {
       return TRUE;
@@ -3955,7 +4434,7 @@ check_oom_check2_func (void *data)
 
   if (! (* d->func) (d->context, d->connection))
     return FALSE;
-  
+
   if (!check_no_leftovers (d->context))
     {
       _dbus_warn ("Messages were left over, should be covered by test suite\n");
@@ -3976,7 +4455,7 @@ check2_try_iterations (BusContext     *context,
   d.func = func;
   d.context = context;
   d.connection = connection;
-  
+
   if (!_dbus_test_oom_handling (description, check_oom_check2_func,
                                 &d))
     {
@@ -3985,8 +4464,44 @@ check2_try_iterations (BusContext     *context,
     }
 }
 
-dbus_bool_t
-bus_dispatch_test (const DBusString *test_data_dir)
+static dbus_bool_t
+setenv_TEST_LAUNCH_HELPER_CONFIG(const DBusString *test_data_dir,
+                                 const char       *filename)
+{
+  DBusString full;
+  DBusString file;
+
+  if (!_dbus_string_init (&full))
+    return FALSE;
+
+  if (!_dbus_string_copy (test_data_dir, 0, &full, 0))
+    {
+      _dbus_string_free (&full);
+      return FALSE;
+    }
+
+  _dbus_string_init_const (&file, filename);
+
+  if (!_dbus_concat_dir_and_file (&full, &file))
+    {
+      _dbus_string_free (&full);
+      return FALSE;
+    }
+
+  _dbus_verbose ("Setting TEST_LAUNCH_HELPER_CONFIG to '%s'\n",
+                 _dbus_string_get_const_data (&full));
+
+  dbus_setenv ("TEST_LAUNCH_HELPER_CONFIG", _dbus_string_get_const_data (&full));
+
+  _dbus_string_free (&full);
+
+  return TRUE;
+}
+
+static dbus_bool_t
+bus_dispatch_test_conf (const DBusString *test_data_dir,
+                       const char       *filename,
+                       dbus_bool_t       use_launcher)
 {
   BusContext *context;
   DBusConnection *foo;
@@ -3994,14 +4509,17 @@ bus_dispatch_test (const DBusString *test_data_dir)
   DBusConnection *baz;
   DBusError error;
 
+  /* save the config name for the activation helper */
+  if (!setenv_TEST_LAUNCH_HELPER_CONFIG (test_data_dir, filename))
+    _dbus_assert_not_reached ("no memory setting TEST_LAUNCH_HELPER_CONFIG");
+
   dbus_error_init (&error);
-  
-  context = bus_context_new_test (test_data_dir,
-                                  "valid-config-files/debug-allow-all.conf");
+
+  context = bus_context_new_test (test_data_dir, filename);
   if (context == NULL)
     return FALSE;
-  
-  foo = dbus_connection_open_private ("debug-pipe:name=test-server", &error);
+
+  foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (foo == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4009,7 +4527,7 @@ bus_dispatch_test (const DBusString *test_data_dir)
     _dbus_assert_not_reached ("could not set up connection");
 
   spin_connection_until_authenticated (context, foo);
-  
+
   if (!check_hello_message (context, foo))
     _dbus_assert_not_reached ("hello message failed");
 
@@ -4018,8 +4536,8 @@ bus_dispatch_test (const DBusString *test_data_dir)
 
   if (!check_add_match_all (context, foo))
     _dbus_assert_not_reached ("AddMatch message failed");
-  
-  bar = dbus_connection_open_private ("debug-pipe:name=test-server", &error);
+
+  bar = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (bar == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4027,14 +4545,14 @@ bus_dispatch_test (const DBusString *test_data_dir)
     _dbus_assert_not_reached ("could not set up connection");
 
   spin_connection_until_authenticated (context, bar);
-  
+
   if (!check_hello_message (context, bar))
     _dbus_assert_not_reached ("hello message failed");
 
   if (!check_add_match_all (context, bar))
     _dbus_assert_not_reached ("AddMatch message failed");
-  
-  baz = dbus_connection_open_private ("debug-pipe:name=test-server", &error);
+
+  baz = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (baz == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4042,31 +4560,36 @@ bus_dispatch_test (const DBusString *test_data_dir)
     _dbus_assert_not_reached ("could not set up connection");
 
   spin_connection_until_authenticated (context, baz);
-  
+
   if (!check_hello_message (context, baz))
     _dbus_assert_not_reached ("hello message failed");
 
   if (!check_add_match_all (context, baz))
     _dbus_assert_not_reached ("AddMatch message failed");
 
+#ifdef DBUS_WIN_FIXME
+  _dbus_warn("TODO: testing of GetConnectionUnixUser message skipped for now\n");
+  _dbus_warn("TODO: testing of GetConnectionUnixProcessID message skipped for now\n");
+#else
   if (!check_get_connection_unix_user (context, baz))
     _dbus_assert_not_reached ("GetConnectionUnixUser message failed");
 
   if (!check_get_connection_unix_process_id (context, baz))
     _dbus_assert_not_reached ("GetConnectionUnixProcessID message failed");
+#endif
 
   if (!check_list_services (context, baz))
     _dbus_assert_not_reached ("ListActivatableNames message failed");
-  
+
   if (!check_no_leftovers (context))
     {
       _dbus_warn ("Messages were left over after setting up initial connections\n");
       _dbus_assert_not_reached ("initial connection setup failed");
     }
-  
+
   check1_try_iterations (context, "create_and_hello",
                          check_hello_connection);
-  
+
   check2_try_iterations (context, foo, "nonexistent_service_no_auto_start",
                          check_nonexistent_service_no_auto_start);
 
@@ -4076,24 +4599,31 @@ bus_dispatch_test (const DBusString *test_data_dir)
   check2_try_iterations (context, foo, "segfault_service_no_auto_start",
                          check_segfault_service_no_auto_start);
 #endif
-  
+
   check2_try_iterations (context, foo, "existent_service_no_auto_start",
                          check_existent_service_no_auto_start);
-  
+
   check2_try_iterations (context, foo, "nonexistent_service_auto_start",
                          check_nonexistent_service_auto_start);
-  
 
-#ifdef DBUS_WIN_FIXME    
+
+#ifdef DBUS_WIN_FIXME
   _dbus_warn("TODO: dispatch.c segfault_service_auto_start test\n");
 #else
+  /* only do the segfault test if we are not using the launcher */
   check2_try_iterations (context, foo, "segfault_service_auto_start",
                          check_segfault_service_auto_start);
 #endif
 
+  /* only do the shell fail test if we are not using the launcher */
   check2_try_iterations (context, foo, "shell_fail_service_auto_start",
                          check_shell_fail_service_auto_start);
 
+  /* specific to launcher */
+  if (use_launcher)
+    if (!check_launch_service_file_missing (context, foo))
+      _dbus_assert_not_reached ("did not get service file not found error");
+
 #if 0
   /* Note: need to resolve some issues with the testing code in order to run
    * this in oom (handle that we sometimes don't get replies back from the bus
@@ -4102,7 +4632,7 @@ bus_dispatch_test (const DBusString *test_data_dir)
   check2_try_iterations (context, foo, "existent_service_auto_auto_start",
                          check_existent_service_auto_start);
 #endif
-  
+
   if (!check_existent_service_auto_start (context, foo))
     _dbus_assert_not_reached ("existent service auto start failed");
 
@@ -4116,7 +4646,91 @@ bus_dispatch_test (const DBusString *test_data_dir)
   kill_client_connection_unchecked (baz);
 
   bus_context_unref (context);
-  
+
+  return TRUE;
+}
+
+static dbus_bool_t
+bus_dispatch_test_conf_fail (const DBusString *test_data_dir,
+                            const char       *filename)
+{
+  BusContext *context;
+  DBusConnection *foo;
+  DBusError error;
+
+  /* save the config name for the activation helper */
+  if (!setenv_TEST_LAUNCH_HELPER_CONFIG (test_data_dir, filename))
+    _dbus_assert_not_reached ("no memory setting TEST_LAUNCH_HELPER_CONFIG");
+
+  dbus_error_init (&error);
+
+  context = bus_context_new_test (test_data_dir, filename);
+  if (context == NULL)
+    return FALSE;
+
+  foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
+  if (foo == NULL)
+    _dbus_assert_not_reached ("could not alloc connection");
+
+  if (!bus_setup_debug_client (foo))
+    _dbus_assert_not_reached ("could not set up connection");
+
+  spin_connection_until_authenticated (context, foo);
+
+  if (!check_hello_message (context, foo))
+    _dbus_assert_not_reached ("hello message failed");
+
+  if (!check_double_hello_message (context, foo))
+    _dbus_assert_not_reached ("double hello message failed");
+
+  if (!check_add_match_all (context, foo))
+    _dbus_assert_not_reached ("AddMatch message failed");
+
+  /* this only tests the activation.c user check */
+  if (!check_launch_service_user_missing (context, foo))
+    _dbus_assert_not_reached ("user missing did not trigger error");
+
+  /* this only tests the desktop.c exec check */
+  if (!check_launch_service_exec_missing (context, foo))
+    _dbus_assert_not_reached ("exec missing did not trigger error");
+
+  /* this only tests the desktop.c service check */
+  if (!check_launch_service_service_missing (context, foo))
+    _dbus_assert_not_reached ("service missing did not trigger error");
+
+  _dbus_verbose ("Disconnecting foo\n");
+
+  kill_client_connection_unchecked (foo);
+
+  bus_context_unref (context);
+
+  return TRUE;
+}
+
+dbus_bool_t
+bus_dispatch_test (const DBusString *test_data_dir)
+{
+  /* run normal activation tests */
+  _dbus_verbose ("Normal activation tests\n");
+  if (!bus_dispatch_test_conf (test_data_dir,
+                              "valid-config-files/debug-allow-all.conf", FALSE))
+    return FALSE;
+
+#ifdef DBUS_WIN
+  _dbus_warn("Info: Launch helper activation tests skipped because launch-helper is not supported yet\n");
+#else
+  /* run launch-helper activation tests */
+  _dbus_verbose ("Launch helper activation tests\n");
+  if (!bus_dispatch_test_conf (test_data_dir,
+                              "valid-config-files-system/debug-allow-all-pass.conf", TRUE))
+    return FALSE;
+
+  /* run select launch-helper activation tests on broken service files */
+  if (!bus_dispatch_test_conf_fail (test_data_dir,
+                                   "valid-config-files-system/debug-allow-all-fail.conf"))
+    return FALSE;
+#endif
+
   return TRUE;
 }
 
@@ -4128,16 +4742,16 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir)
   DBusError error;
 
   dbus_error_init (&error);
-  
+
   /* Test SHA1 authentication */
   _dbus_verbose ("Testing SHA1 context\n");
-  
+
   context = bus_context_new_test (test_data_dir,
                                   "valid-config-files/debug-allow-all-sha1.conf");
   if (context == NULL)
     return FALSE;
 
-  foo = dbus_connection_open_private ("debug-pipe:name=test-server", &error);
+  foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (foo == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4145,19 +4759,19 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir)
     _dbus_assert_not_reached ("could not set up connection");
 
   spin_connection_until_authenticated (context, foo);
-  
+
   if (!check_hello_message (context, foo))
     _dbus_assert_not_reached ("hello message failed");
 
   if (!check_add_match_all (context, foo))
     _dbus_assert_not_reached ("addmatch message failed");
-  
+
   if (!check_no_leftovers (context))
     {
       _dbus_warn ("Messages were left over after setting up initial SHA-1 connection\n");
       _dbus_assert_not_reached ("initial connection setup failed");
     }
-  
+
   check1_try_iterations (context, "create_and_hello_sha1",
                          check_hello_connection);
 
@@ -4168,4 +4782,154 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir)
   return TRUE;
 }
 
-#endif /* DBUS_BUILD_TESTS */
+#ifdef HAVE_UNIX_FD_PASSING
+
+dbus_bool_t
+bus_unix_fds_passing_test(const DBusString *test_data_dir)
+{
+  BusContext *context;
+  DBusConnection *foo, *bar;
+  DBusError error;
+  DBusMessage *m;
+  int one[2], two[2], x, y, z;
+  char r;
+
+  dbus_error_init (&error);
+
+  context = bus_context_new_test (test_data_dir, "valid-config-files/debug-allow-all.conf");
+  if (context == NULL)
+    _dbus_assert_not_reached ("could not alloc context");
+
+  foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
+  if (foo == NULL)
+    _dbus_assert_not_reached ("could not alloc connection");
+
+  if (!bus_setup_debug_client (foo))
+    _dbus_assert_not_reached ("could not set up connection");
+
+  spin_connection_until_authenticated (context, foo);
+
+  if (!check_hello_message (context, foo))
+    _dbus_assert_not_reached ("hello message failed");
+
+  if (!check_add_match_all (context, foo))
+    _dbus_assert_not_reached ("AddMatch message failed");
+
+  bar = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
+  if (bar == NULL)
+    _dbus_assert_not_reached ("could not alloc connection");
+
+  if (!bus_setup_debug_client (bar))
+    _dbus_assert_not_reached ("could not set up connection");
+
+  spin_connection_until_authenticated (context, bar);
+
+  if (!check_hello_message (context, bar))
+    _dbus_assert_not_reached ("hello message failed");
+
+  if (!check_add_match_all (context, bar))
+    _dbus_assert_not_reached ("AddMatch message failed");
+
+  if (!(m = dbus_message_new_signal("/", "a.b.c", "d")))
+    _dbus_assert_not_reached ("could not alloc message");
+
+  if (!(_dbus_full_duplex_pipe(one, one+1, TRUE, &error)))
+    _dbus_assert_not_reached("Failed to allocate pipe #1");
+
+  if (!(_dbus_full_duplex_pipe(two, two+1, TRUE, &error)))
+    _dbus_assert_not_reached("Failed to allocate pipe #2");
+
+  if (!dbus_message_append_args(m,
+                                DBUS_TYPE_UNIX_FD, one,
+                                DBUS_TYPE_UNIX_FD, two,
+                                DBUS_TYPE_UNIX_FD, two,
+                                DBUS_TYPE_INVALID))
+    _dbus_assert_not_reached("Failed to attach fds.");
+
+  if (!_dbus_close(one[0], &error))
+    _dbus_assert_not_reached("Failed to close pipe #1 ");
+  if (!_dbus_close(two[0], &error))
+    _dbus_assert_not_reached("Failed to close pipe #2 ");
+
+  if (!(dbus_connection_can_send_type(foo, DBUS_TYPE_UNIX_FD)))
+    _dbus_assert_not_reached("Connection cannot do fd passing");
+
+  if (!(dbus_connection_can_send_type(bar, DBUS_TYPE_UNIX_FD)))
+    _dbus_assert_not_reached("Connection cannot do fd passing");
+
+  if (!dbus_connection_send (foo, m, NULL))
+    _dbus_assert_not_reached("Failed to send fds");
+
+  dbus_message_unref(m);
+
+  bus_test_run_clients_loop (SEND_PENDING (foo));
+
+  bus_test_run_everything (context);
+
+  block_connection_until_message_from_bus (context, foo, "unix fd reception on foo");
+
+  if (!(m = pop_message_waiting_for_memory (foo)))
+    _dbus_assert_not_reached("Failed to receive msg");
+
+  if (!dbus_message_is_signal(m, "a.b.c", "d"))
+    _dbus_assert_not_reached("bogus message received");
+
+  dbus_message_unref(m);
+
+  block_connection_until_message_from_bus (context, bar, "unix fd reception on bar");
+
+  if (!(m = pop_message_waiting_for_memory (bar)))
+    _dbus_assert_not_reached("Failed to receive msg");
+
+  if (!dbus_message_is_signal(m, "a.b.c", "d"))
+    _dbus_assert_not_reached("bogus message received");
+
+  if (!dbus_message_get_args(m,
+                             &error,
+                             DBUS_TYPE_UNIX_FD, &x,
+                             DBUS_TYPE_UNIX_FD, &y,
+                             DBUS_TYPE_UNIX_FD, &z,
+                             DBUS_TYPE_INVALID))
+    _dbus_assert_not_reached("Failed to parse fds.");
+
+  dbus_message_unref(m);
+
+  if (write(x, "X", 1) != 1)
+    _dbus_assert_not_reached("Failed to write to pipe #1");
+  if (write(y, "Y", 1) != 1)
+    _dbus_assert_not_reached("Failed to write to pipe #2");
+  if (write(z, "Z", 1) != 1)
+    _dbus_assert_not_reached("Failed to write to pipe #2/2nd fd");
+
+  if (!_dbus_close(x, &error))
+    _dbus_assert_not_reached("Failed to close pipe #1/other side ");
+  if (!_dbus_close(y, &error))
+    _dbus_assert_not_reached("Failed to close pipe #2/other side ");
+  if (!_dbus_close(z, &error))
+    _dbus_assert_not_reached("Failed to close pipe #2/other size 2nd fd ");
+
+  if (read(one[1], &r, 1) != 1 || r != 'X')
+    _dbus_assert_not_reached("Failed to read value from pipe.");
+  if (read(two[1], &r, 1) != 1 || r != 'Y')
+    _dbus_assert_not_reached("Failed to read value from pipe.");
+  if (read(two[1], &r, 1) != 1 || r != 'Z')
+    _dbus_assert_not_reached("Failed to read value from pipe.");
+
+  if (!_dbus_close(one[1], &error))
+    _dbus_assert_not_reached("Failed to close pipe #1 ");
+  if (!_dbus_close(two[1], &error))
+    _dbus_assert_not_reached("Failed to close pipe #2 ");
+
+  _dbus_verbose ("Disconnecting foo\n");
+  kill_client_connection_unchecked (foo);
+
+  _dbus_verbose ("Disconnecting bar\n");
+  kill_client_connection_unchecked (bar);
+
+  bus_context_unref (context);
+
+  return TRUE;
+}
+#endif
+
+#endif /* DBUS_ENABLE_EMBEDDED_TESTS */