[lib-fix] moved dbus_connection_get_unix_user from daemon to library
[platform/upstream/dbus.git] / bus / services.c
index f8124b0..90a2f5f 100644 (file)
@@ -1,9 +1,11 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* services.c  Service management
  *
  * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  CodeFactory AB
+ * Copyright (C) 2013  Samsung Electronics
  *
- * Licensed under the Academic Free License version 1.2
+ * 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
  * 
  * 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 "services.h"
-#include "connection.h"
+
+#include <config.h>
 #include <dbus/dbus-hash.h>
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-mempool.h>
+#include <dbus/dbus-marshal-validate.h>
+#include "driver.h"
+#include "services.h"
+#include "connection.h"
+#include "utils.h"
+#include "activation.h"
+#include "policy.h"
+#include "bus.h"
+#include "selinux.h"
+
+#ifdef ENABLE_KDBUS_TRANSPORT
+#include <linux/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include "kdbus-d.h"
+#include "dbus/kdbus.h"
+#include "dbus/kdbus-common.h"
+#endif
 
 struct BusService
 {
+  int refcount;
+
+  BusRegistry *registry;
   char *name;
   DBusList *owners;
 };
 
-static DBusHashTable *service_hash = NULL;
-static DBusMemPool   *service_pool = NULL;
+struct BusOwner
+{
+  int refcount;
+
+  BusService *service;
+  DBusConnection *conn;
+
+  unsigned int allow_replacement : 1;
+  unsigned int do_not_queue : 1;
+#ifdef ENABLE_KDBUS_TRANSPORT
+  unsigned int is_kdbus_starter : 1;
+#endif
+};
+
+struct BusRegistry
+{
+  int refcount;
+
+  BusContext *context;
+  
+  DBusHashTable *service_hash;
+  DBusMemPool   *service_pool;
+  DBusMemPool   *owner_pool;
+
+  DBusHashTable *service_sid_table;
+};
+
+BusRegistry*
+bus_registry_new (BusContext *context)
+{
+  BusRegistry *registry;
+
+  registry = dbus_new0 (BusRegistry, 1);
+  if (registry == NULL)
+    return NULL;
+
+  registry->refcount = 1;
+  registry->context = context;
+  
+  registry->service_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
+                                                 NULL, NULL);
+  if (registry->service_hash == NULL)
+    goto failed;
+  
+  registry->service_pool = _dbus_mem_pool_new (sizeof (BusService),
+                                               TRUE);
+
+  if (registry->service_pool == NULL)
+    goto failed;
+
+  registry->owner_pool = _dbus_mem_pool_new (sizeof (BusOwner),
+                                             TRUE);
+
+  if (registry->owner_pool == NULL)
+    goto failed;
+
+  registry->service_sid_table = NULL;
+  
+  return registry;
+
+ failed:
+  bus_registry_unref (registry);
+  return NULL;
+}
+
+BusRegistry *
+bus_registry_ref (BusRegistry *registry)
+{
+  _dbus_assert (registry->refcount > 0);
+  registry->refcount += 1;
+
+  return registry;
+}
+
+void
+bus_registry_unref  (BusRegistry *registry)
+{
+  _dbus_assert (registry->refcount > 0);
+  registry->refcount -= 1;
+
+  if (registry->refcount == 0)
+    {
+      if (registry->service_hash)
+        _dbus_hash_table_unref (registry->service_hash);
+      if (registry->service_pool)
+        _dbus_mem_pool_free (registry->service_pool);
+      if (registry->owner_pool)
+        _dbus_mem_pool_free (registry->owner_pool);
+      if (registry->service_sid_table)
+        _dbus_hash_table_unref (registry->service_sid_table);
+      
+      dbus_free (registry);
+    }
+}
 
 BusService*
-bus_service_lookup (const DBusString *service_name,
-                    dbus_bool_t       create_if_not_found)
+bus_registry_lookup (BusRegistry      *registry,
+                     const DBusString *service_name)
 {
-  const char *c_name;
   BusService *service;
+
+  service = _dbus_hash_table_lookup_string (registry->service_hash,
+                                            _dbus_string_get_const_data (service_name));
+
+  return service;
+}
+
+static DBusList *
+_bus_service_find_owner_link (BusService *service,
+                              DBusConnection *connection)
+{
+  DBusList *link;
   
-  if (service_hash == NULL)
+  link = _dbus_list_get_first_link (&service->owners);
+
+  while (link != NULL)
+    {
+      BusOwner *bus_owner;
+
+      bus_owner = (BusOwner *) link->data;
+      if (bus_owner->conn == connection) 
+        break;
+
+      link = _dbus_list_get_next_link (&service->owners, link);
+    }
+
+  return link;
+}
+
+#ifdef ENABLE_KDBUS_TRANSPORT
+static DBusConnection *
+_bus_service_find_owner_connection (BusService *service,
+                                   const char* unique_name)
+{
+  DBusList *link;
+
+  link = _dbus_list_get_first_link (&service->owners);
+
+  while (link != NULL)
+    {
+      BusOwner *bus_owner;
+
+      bus_owner = (BusOwner *) link->data;
+      if(!strcmp(bus_connection_get_name(bus_owner->conn), unique_name))
+          return bus_owner->conn;
+
+      link = _dbus_list_get_next_link (&service->owners, link);
+    }
+
+  return NULL;
+}
+#endif
+
+static void
+bus_owner_set_flags (BusOwner *owner,
+                     dbus_uint32_t flags)
+{
+   owner->allow_replacement = 
+        (flags & DBUS_NAME_FLAG_ALLOW_REPLACEMENT) != FALSE;
+
+   owner->do_not_queue =
+        (flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) != FALSE;
+
+#ifdef ENABLE_KDBUS_TRANSPORT
+   owner->is_kdbus_starter =
+        (flags & KDBUS_NAME_STARTER_NAME) != FALSE;
+#endif
+}
+
+static BusOwner *
+bus_owner_new (BusService *service, 
+               DBusConnection *conn, 
+              dbus_uint32_t flags)
+{
+  BusOwner *result;
+
+  result = _dbus_mem_pool_alloc (service->registry->owner_pool);
+  if (result != NULL)
     {
-      service_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
-                                           NULL, NULL);
-      service_pool = _dbus_mem_pool_new (sizeof (BusService),
-                                         TRUE);
+      result->refcount = 1;
+      /* don't ref the connection because we don't want
+         to block the connection from going away.
+         transactions take care of reffing the connection
+         but we need to use refcounting on the owner
+         so that the owner does not get freed before
+         we can deref the connection in the transaction
+       */
+      result->conn = conn;
+      result->service = service;
 
-      if (service_hash == NULL || service_pool == NULL)
+      if (!bus_connection_add_owned_service (conn, service))
         {
-          if (service_hash)
-            {
-              _dbus_hash_table_unref (service_hash);
-              service_hash = NULL;
-            }
-          if (service_pool)
-            {
-              _dbus_mem_pool_free (service_pool);
-              service_pool = NULL;
-            }
+          _dbus_mem_pool_dealloc (service->registry->owner_pool, result);
           return NULL;
         }
+        
+      bus_owner_set_flags (result, flags);
+    }
+  return result;
+}
+
+static BusOwner *
+bus_owner_ref (BusOwner *owner)
+{
+  _dbus_assert (owner->refcount > 0);
+  owner->refcount += 1;
+
+  return owner;
+}
+
+static void
+bus_owner_unref  (BusOwner *owner)
+{
+  _dbus_assert (owner->refcount > 0);
+  owner->refcount -= 1;
+
+  if (owner->refcount == 0)
+    {
+      bus_connection_remove_owned_service (owner->conn, owner->service);
+      _dbus_mem_pool_dealloc (owner->service->registry->owner_pool, owner);
     }
+}
+
+BusService*
+bus_registry_ensure (BusRegistry               *registry,
+                     const DBusString          *service_name,
+                     DBusConnection            *owner_connection_if_created,
+                     dbus_uint32_t              flags,
+                     BusTransaction            *transaction,
+                     DBusError                 *error)
+{
+  BusService *service;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   
-  _dbus_string_get_const_data (service_name, &c_name);
+  _dbus_assert (owner_connection_if_created != NULL);
+  _dbus_assert (transaction != NULL);
 
-  service = _dbus_hash_table_lookup_string (service_hash,
-                                            c_name);
+  service = _dbus_hash_table_lookup_string (registry->service_hash,
+                                            _dbus_string_get_const_data (service_name));
   if (service != NULL)
     return service;
-
-  if (!create_if_not_found)
-    return NULL;
   
-  service = _dbus_mem_pool_alloc (service_pool);
+  service = _dbus_mem_pool_alloc (registry->service_pool);
   if (service == NULL)
-    return NULL;
+    {
+      BUS_SET_OOM (error);
+      return NULL;
+    }
+
+  service->registry = registry;  
+  service->refcount = 1;
+
+  _dbus_verbose ("copying string %p '%s' to service->name\n",
+                 service_name, _dbus_string_get_const_data (service_name));
+  if (!_dbus_string_copy_data (service_name, &service->name))
+    {
+      _dbus_mem_pool_dealloc (registry->service_pool, service);
+      BUS_SET_OOM (error);
+      return NULL;
+    }
+  _dbus_verbose ("copied string %p '%s' to '%s'\n",
+                 service_name, _dbus_string_get_const_data (service_name),
+                 service->name);
 
-  service->name = _dbus_strdup (c_name);
-  if (service->name == NULL)
+  if (!bus_driver_send_service_owner_changed (service->name, 
+                                             NULL,
+                                             bus_connection_get_name (owner_connection_if_created),
+                                             transaction, error))
     {
-      _dbus_mem_pool_dealloc (service_pool, service);
+      bus_service_unref (service);
       return NULL;
     }
 
-  if (!_dbus_hash_table_insert_string (service_hash,
+  if (!bus_activation_service_created (bus_context_get_activation (registry->context),
+                                      service->name, transaction, error))
+    {
+      bus_service_unref (service);
+      return NULL;
+    }
+  
+  if (!bus_service_add_owner (service, owner_connection_if_created, flags,
+                                              transaction, error))
+    {
+      bus_service_unref (service);
+      return NULL;
+    }
+  
+  if (!_dbus_hash_table_insert_string (registry->service_hash,
                                        service->name,
                                        service))
     {
-      dbus_free (service->name);
-      _dbus_mem_pool_dealloc (service_pool, service);
+      /* The add_owner gets reverted on transaction cancel */
+      BUS_SET_OOM (error);
       return NULL;
     }
 
   return service;
 }
 
+void
+bus_registry_foreach (BusRegistry               *registry,
+                      BusServiceForeachFunction  function,
+                      void                      *data)
+{
+  DBusHashIter iter;
+  
+  _dbus_hash_iter_init (registry->service_hash, &iter);
+  while (_dbus_hash_iter_next (&iter))
+    {
+      BusService *service = _dbus_hash_iter_get_value (&iter);
+
+      (* function) (service, data);
+    }
+}
+
 dbus_bool_t
-bus_service_add_owner (BusService     *service,
-                       DBusConnection *owner)
+bus_registry_list_services (BusRegistry *registry,
+                            char      ***listp,
+                            int         *array_len)
 {
-  if (!_dbus_list_append (&service->owners,
-                          owner))
+  int i, j, len;
+  char **retval;
+  DBusHashIter iter;
+   
+  len = _dbus_hash_table_get_n_entries (registry->service_hash);
+  retval = dbus_new (char *, len + 1);
+
+  if (retval == NULL)
     return FALSE;
 
-  if (!bus_connection_add_owned_service (owner, service))
+  _dbus_hash_iter_init (registry->service_hash, &iter);
+  i = 0;
+  while (_dbus_hash_iter_next (&iter))
     {
-      _dbus_list_remove_last (&service->owners, owner);
-      return FALSE;
+      BusService *service = _dbus_hash_iter_get_value (&iter);
+
+      retval[i] = _dbus_strdup (service->name);
+      if (retval[i] == NULL)
+       goto error;
+
+      i++;
     }
 
+  retval[i] = NULL;
+  
+  if (array_len)
+    *array_len = len;
+  
+  *listp = retval;
   return TRUE;
-}
+  
+ error:
+  for (j = 0; j < i; j++)
+    dbus_free (retval[j]);
+  dbus_free (retval);
 
-void
-bus_service_remove_owner (BusService     *service,
-                          DBusConnection *owner)
-{
-  _dbus_list_remove_last (&service->owners, owner);
-  bus_connection_remove_owned_service (owner, service);
+  return FALSE;
 }
 
-DBusConnection*
-bus_service_get_primary_owner (BusService *service)
+dbus_bool_t
+bus_registry_acquire_service (BusRegistry      *registry,
+                              DBusConnection   *connection,
+                              const DBusString *service_name,
+                              dbus_uint32_t     flags,
+                              dbus_uint32_t    *result,
+                              BusTransaction   *transaction,
+                              DBusError        *error)
 {
-  return _dbus_list_get_first (&service->owners);
+  dbus_bool_t retval;
+  DBusConnection *old_owner_conn;
+  BusClientPolicy *policy;
+  BusService *service;
+  BusActivation  *activation;
+  BusSELinuxID *sid;
+  BusOwner *primary_owner;
+  retval = FALSE;
+
+  if (!_dbus_validate_bus_name (service_name, 0,
+                                _dbus_string_get_length (service_name)))
+    {
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Requested bus name \"%s\" is not valid",
+                      _dbus_string_get_const_data (service_name));
+      
+      _dbus_verbose ("Attempt to acquire invalid service name\n");
+      
+      goto out;
+    }
+  
+  if (_dbus_string_get_byte (service_name, 0) == ':')
+    {
+      /* Not allowed; only base services can start with ':' */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Cannot acquire a service starting with ':' such as \"%s\"",
+                      _dbus_string_get_const_data (service_name));
+      
+      _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"",
+                     _dbus_string_get_const_data (service_name));
+      
+      goto out;
+    }
+
+  if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS))
+    {
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Connection \"%s\" is not allowed to own the service \"%s\"because "
+                      "it is reserved for D-Bus' use only",
+                      bus_connection_is_active (connection) ?
+                      bus_connection_get_name (connection) :
+                      "(inactive)",
+                      DBUS_SERVICE_DBUS);
+      goto out;
+    }
+
+  policy = bus_connection_get_policy (connection);
+  _dbus_assert (policy != NULL);
+
+  /* Note that if sid is #NULL then the bus's own context gets used
+   * in bus_connection_selinux_allows_acquire_service()
+   */
+  sid = bus_selinux_id_table_lookup (registry->service_sid_table,
+                                                                        service_name);
+
+  if (!bus_selinux_allows_acquire_service (connection, sid,
+                                          _dbus_string_get_const_data (service_name), error))
+       {
+
+         if (dbus_error_is_set (error) &&
+         dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY))
+       {
+         goto out;
+       }
+
+         dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+                                         "Connection \"%s\" is not allowed to own the service \"%s\" due "
+                                         "to SELinux policy",
+                                         bus_connection_is_active (connection) ?
+                                         bus_connection_get_name (connection) :
+                                         "(inactive)",
+                                         _dbus_string_get_const_data (service_name));
+         goto out;
+       }
+
+  if (!bus_client_policy_check_can_own (policy, service_name))
+       {
+         dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+                                         "Connection \"%s\" is not allowed to own the service \"%s\" due "
+                                         "to security policies in the configuration file",
+                                         bus_connection_is_active (connection) ?
+                                         bus_connection_get_name (connection) :
+                                         "(inactive)",
+                                         _dbus_string_get_const_data (service_name));
+         goto out;
+       }
+
+  if (bus_connection_get_n_services_owned (connection) >=
+         bus_context_get_max_services_per_connection (registry->context))
+       {
+         dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
+                                         "Connection \"%s\" is not allowed to own more services "
+                                         "(increase limits in configuration file if required)",
+                                         bus_connection_is_active (connection) ?
+                                         bus_connection_get_name (connection) :
+                                         "(inactive)");
+         goto out;
+       }
+
+  service = bus_registry_lookup (registry, service_name);
+
+  if (service != NULL)
+       {
+         primary_owner = bus_service_get_primary_owner (service);
+         if (primary_owner != NULL)
+               old_owner_conn = primary_owner->conn;
+         else
+               old_owner_conn = NULL;
+       }
+  else
+       old_owner_conn = NULL;
+
+  if (service == NULL)
+       {
+         service = bus_registry_ensure (registry,
+                                                                        service_name, connection, flags,
+                                                                        transaction, error);
+         if (service == NULL)
+               goto out;
+       }
+
+  primary_owner = bus_service_get_primary_owner (service);
+  if (primary_owner == NULL)
+       goto out;
+
+  if (old_owner_conn == NULL)
+       {
+         _dbus_assert (primary_owner->conn == connection);
+
+         *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
+       }
+  else if (old_owner_conn == connection)
+       {
+         bus_owner_set_flags (primary_owner, flags);
+         *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
+       }
+  else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
+                  !(bus_service_get_allow_replacement (service))) ||
+          ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
+                  !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING)))
+       {
+         DBusList *link;
+         BusOwner *temp_owner;
+       /* Since we can't be queued if we are already in the queue
+          remove us */
+
+         link = _bus_service_find_owner_link (service, connection);
+         if (link != NULL)
+               {
+                 _dbus_list_unlink (&service->owners, link);
+                 temp_owner = (BusOwner *)link->data;
+                 bus_owner_unref (temp_owner);
+                 _dbus_list_free_link (link);
+               }
+
+         *result = DBUS_REQUEST_NAME_REPLY_EXISTS;
+       }
+  else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
+                  (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) ||
+               !(bus_service_get_allow_replacement (service))))
+       {
+         /* Queue the connection */
+         if (!bus_service_add_owner (service, connection,
+                                                                 flags,
+                                                                 transaction, error))
+               goto out;
+
+         *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE;
+       }
+  else
+       {
+         /* Replace the current owner */
+
+         /* We enqueue the new owner and remove the first one because
+          * that will cause NameAcquired and NameLost messages to
+          * be sent.
+          */
+
+         if (!bus_service_add_owner (service, connection,
+                                                                 flags,
+                                                                 transaction, error))
+               goto out;
+
+         if (primary_owner->do_not_queue)
+               {
+                 if (!bus_service_remove_owner (service, old_owner_conn,
+                                                                                transaction, error))
+                       goto out;
+               }
+         else
+               {
+                 if (!bus_service_swap_owner (service, old_owner_conn,
+                                                                          transaction, error))
+                       goto out;
+               }
+
+
+         _dbus_assert (connection == bus_service_get_primary_owner (service)->conn);
+         *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
+       }
+
+  activation = bus_context_get_activation (registry->context);
+  retval = bus_activation_send_pending_auto_activation_messages (activation,
+                                                                service,
+                                                                transaction,
+                                                                error);
+
+ out:
+  return retval;
 }
 
-const char*
-bus_service_get_name (BusService *service)
+#ifdef ENABLE_KDBUS_TRANSPORT
+dbus_bool_t
+bus_registry_acquire_kdbus_service (BusRegistry      *registry,
+                              DBusConnection   *connection,
+                              DBusMessage *message,
+                              dbus_uint32_t    *result,
+                              BusTransaction   *transaction,
+                              DBusError        *error)
 {
-  return service->name;
+  dbus_bool_t retval;
+  BusService *service;
+  BusActivation  *activation;
+  DBusString service_name_real;
+  const DBusString *service_name = &service_name_real;
+  char* name;
+  dbus_uint32_t flags;
+  __u64 sender_id;
+  const char* conn_unique_name;
+  DBusConnection* phantom;
+  unsigned long int uid;
+
+  if (!dbus_message_get_args (message, error,
+                              DBUS_TYPE_STRING, &name,
+                              DBUS_TYPE_UINT32, &flags,
+                              DBUS_TYPE_INVALID))
+    return FALSE;
+
+  retval = FALSE;
+
+  _dbus_string_init_const (&service_name_real, name);
+
+  if (!_dbus_validate_bus_name (service_name, 0,
+                                _dbus_string_get_length (service_name)))
+    {
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Requested bus name \"%s\" is not valid", name);
+
+      _dbus_verbose ("Attempt to acquire invalid service name\n");
+
+      return FALSE;
+    }
+
+  if (_dbus_string_get_byte (service_name, 0) == ':')
+    {
+      /* Not allowed; only base services can start with ':' */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Cannot acquire a service starting with ':' such as \"%s\"", name);
+
+      _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"", name);
+
+      return FALSE;
+    }
+
+  conn_unique_name = dbus_message_get_sender(message);
+
+  if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS))
+    {
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Connection \"%s\" is not allowed to own the service \"%s\"because "
+                      "it is reserved for D-Bus' use only",
+                      conn_unique_name, DBUS_SERVICE_DBUS);
+      return FALSE;
+    }
+
+  sender_id = sender_name_to_id(conn_unique_name, error);
+  if(dbus_error_is_set(error))
+    return FALSE;
+
+  phantom = bus_connections_find_conn_by_name(bus_connection_get_connections(connection), conn_unique_name);
+  if(phantom == NULL)
+    {
+      phantom = create_phantom_connection(connection, conn_unique_name, error);
+      if(phantom == NULL)
+        return FALSE;
+    }
+
+  if (!bus_client_policy_check_can_own (bus_connection_get_policy (phantom), service_name))
+    {
+      dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+          "Connection \"%s\" is not allowed to own the service \"%s\" due "
+          "to security policies in the configuration file", conn_unique_name, name);
+      goto failed;
+    }
+
+  if (!kdbus_connection_get_unix_user(phantom, conn_unique_name, &uid, NULL))
+    goto failed;
+
+#ifdef POLICY_TO_KDBUS
+  if (!register_kdbus_policy(name, dbus_connection_get_transport(phantom), uid))
+  {
+    dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+            "Kdbus error when setting policy for connection \"%s\" and  service name \"%s\"",
+            conn_unique_name, name);
+    goto failed;
+  }
+#endif
+
+  *result = kdbus_request_name(connection, service_name, flags, sender_id);
+  if(*result == -EPERM)
+    {
+      dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+          "Kdbus not allowed %s to own the service \"%s\"",
+          conn_unique_name, _dbus_string_get_const_data (service_name));
+      goto failed;
+    }
+  else if(*result < 0)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED , "Name \"%s\" could not be acquired", name);
+      goto failed;
+    }
+
+  if((*result == DBUS_REQUEST_NAME_REPLY_IN_QUEUE) || (*result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER))
+    {
+      service = bus_registry_lookup (registry, service_name);
+      if (service == NULL)
+        {
+          service = bus_registry_ensure (registry, service_name, phantom, flags,
+                       transaction, error);
+          if (service == NULL)
+            goto failed2;
+        }
+      else
+        {
+          if (!bus_service_add_owner (service, phantom, flags, transaction, error))
+            goto failed2;
+        }
+
+      activation = bus_context_get_activation (registry->context);
+      retval = bus_activation_send_pending_auto_activation_messages (activation,
+                   service,
+                   transaction,
+                   error);
+    }
+  else
+    retval = TRUE;
+
+  return retval;
+  
+failed2:
+  kdbus_release_name(phantom, service_name, sender_id);
+failed:
+  bus_connection_disconnected(phantom);
+
+  return FALSE;
 }
+#endif
 
-void
-bus_service_foreach (BusServiceForeachFunction  function,
-                     void                      *data)
+dbus_bool_t
+bus_registry_release_service (BusRegistry      *registry,
+                              DBusConnection   *connection,
+                              const DBusString *service_name,
+                              dbus_uint32_t    *result,
+                              BusTransaction   *transaction,
+                              DBusError        *error)
 {
-  DBusHashIter iter;
-  
-  if (service_hash == NULL)
-    return;
-  
-  _dbus_hash_iter_init (service_hash, &iter);
-  while (_dbus_hash_iter_next (&iter))
+  dbus_bool_t retval;
+  BusService *service;
+
+  retval = FALSE;
+
+  if (!_dbus_validate_bus_name (service_name, 0,
+                                _dbus_string_get_length (service_name)))
     {
-      BusService *service = _dbus_hash_iter_get_value (&iter);
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Given bus name \"%s\" is not valid",
+                      _dbus_string_get_const_data (service_name));
 
-      (* function) (service, data);
+      _dbus_verbose ("Attempt to release invalid service name\n");
+
+      goto out;
+    }
+
+  if (_dbus_string_get_byte (service_name, 0) == ':')
+    {
+      /* Not allowed; the base service name cannot be created or released */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Cannot release a service starting with ':' such as \"%s\"",
+                      _dbus_string_get_const_data (service_name));
+
+      _dbus_verbose ("Attempt to release invalid base service name \"%s\"",
+                     _dbus_string_get_const_data (service_name));
+
+      goto out;
+    }
+
+   if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS))
+    {
+      /* Not allowed; the base service name cannot be created or released */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Cannot release the %s service because it is owned by the bus",
+                     DBUS_SERVICE_DBUS);
+
+      _dbus_verbose ("Attempt to release service name \"%s\"",
+                     DBUS_SERVICE_DBUS);
+
+      goto out;
     }
+
+  service = bus_registry_lookup (registry, service_name);
+
+  if (service == NULL)
+    {
+      *result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT;
+    }
+  else if (!bus_service_has_owner (service, connection))
+    {
+      *result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER;
+    }
+  else
+    {
+      if (!bus_service_remove_owner (service, connection,
+                                     transaction, error))
+        goto out;
+
+      _dbus_assert (!bus_service_has_owner (service, connection));
+      *result = DBUS_RELEASE_NAME_REPLY_RELEASED;
+    }
+
+  retval = TRUE;
+
+ out:
+  return retval;
+}
+
+#ifdef ENABLE_KDBUS_TRANSPORT
+dbus_bool_t
+bus_registry_release_service_kdbus (const char* sender_name,
+                              DBusConnection   *connection,
+                              const DBusString *service_name,
+                              dbus_uint32_t    *result,
+                              BusTransaction   *transaction,
+                              DBusError        *error)
+{
+  dbus_bool_t retval = FALSE;
+  __u64 sender_id;
+
+  if (!_dbus_validate_bus_name (service_name, 0,
+                                _dbus_string_get_length (service_name)))
+    {
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Given bus name \"%s\" is not valid",
+                      _dbus_string_get_const_data (service_name));
+
+      _dbus_verbose ("Attempt to release invalid service name\n");
+
+      goto out;
+    }
+
+  if (_dbus_string_get_byte (service_name, 0) == ':')
+    {
+      /* Not allowed; the base service name cannot be created or released */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Cannot release a service starting with ':' such as \"%s\"",
+                      _dbus_string_get_const_data (service_name));
+
+      _dbus_verbose ("Attempt to release invalid base service name \"%s\"",
+                     _dbus_string_get_const_data (service_name));
+
+      goto out;
+    }
+
+   if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS))
+    {
+      /* Not allowed; the base service name cannot be created or released */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Cannot release the %s service because it is owned by the bus",
+                     DBUS_SERVICE_DBUS);
+
+      _dbus_verbose ("Attempt to release service name \"%s\"",
+                     DBUS_SERVICE_DBUS);
+
+      goto out;
+    }
+
+    sender_id = sender_name_to_id(sender_name, error);
+    if(dbus_error_is_set(error))
+        return FALSE;
+
+    *result = kdbus_release_name(connection, service_name, sender_id);
+
+    if(*result == DBUS_RELEASE_NAME_REPLY_RELEASED)
+    {
+        BusRegistry* registry;
+        BusService *service;
+
+        registry = bus_connection_get_registry (connection);
+        service = bus_registry_lookup (registry, service_name);
+        if(service)
+        {
+            DBusConnection* phantom;
+
+            phantom = _bus_service_find_owner_connection(service, sender_name);
+            if(phantom)
+            {
+                bus_service_remove_owner (service, phantom, transaction, NULL);
+                /* todo we could remove phantom if he doesn't own any name
+                 * to do this we should write function in connection.c to check if
+                 * _dbus_list_get_last (&d->services_owned) returns not NULL
+                 *  or we can leave phantom - he will be removed when he disconnects from the bus
+                 */
+            }
+            else
+                _dbus_verbose ("Didn't find phantom connection for released name!\n");
+        }
+   }
+
+  retval = TRUE;
+
+ out:
+  return retval;
+}
+#endif
+
+dbus_bool_t
+bus_registry_set_service_context_table (BusRegistry   *registry,
+                                       DBusHashTable *table)
+{
+  DBusHashTable *new_table;
+  DBusHashIter iter;
+  
+  new_table = bus_selinux_id_table_new ();
+  if (!new_table)
+    return FALSE;
+
+  _dbus_hash_iter_init (table, &iter);
+  while (_dbus_hash_iter_next (&iter))
+    {
+      const char *service = _dbus_hash_iter_get_string_key (&iter);
+      const char *context = _dbus_hash_iter_get_value (&iter);
+
+      if (!bus_selinux_id_table_insert (new_table,
+                                       service,
+                                       context))
+       return FALSE;
+    }
+  
+  if (registry->service_sid_table)
+    _dbus_hash_table_unref (registry->service_sid_table);
+  registry->service_sid_table = new_table;
+  return TRUE;
+}
+
+static void
+bus_service_unlink_owner (BusService      *service,
+                          BusOwner        *owner)
+{
+  _dbus_list_remove_last (&service->owners, owner);
+  bus_owner_unref (owner);
+}
+
+static void
+bus_service_unlink (BusService *service)
+{
+  _dbus_assert (service->owners == NULL);
+
+  /* the service may not be in the hash, if
+   * the failure causing transaction cancel
+   * was in the right place, but that's OK
+   */
+  _dbus_hash_table_remove_string (service->registry->service_hash,
+                                  service->name);
+  
+  bus_service_unref (service);
+}
+
+static void
+bus_service_relink (BusService           *service,
+                    DBusPreallocatedHash *preallocated)
+{
+  _dbus_assert (service->owners == NULL);
+  _dbus_assert (preallocated != NULL);
+
+  _dbus_hash_table_insert_string_preallocated (service->registry->service_hash,
+                                               preallocated,
+                                               service->name,
+                                               service);
+  
+  bus_service_ref (service);
+}
+
+/**
+ * Data used to represent an ownership cancellation in
+ * a bus transaction.
+ */
+typedef struct
+{
+  BusOwner *owner;            /**< the owner */
+  BusService *service;        /**< service to cancel ownership of */
+} OwnershipCancelData;
+
+static void
+cancel_ownership (void *data)
+{
+  OwnershipCancelData *d = data;
+
+  /* We don't need to send messages notifying of these
+   * changes, since we're reverting something that was
+   * cancelled (effectively never really happened)
+   */
+  bus_service_unlink_owner (d->service, d->owner);
+  
+  if (d->service->owners == NULL)
+    bus_service_unlink (d->service);
+}
+
+static void
+free_ownership_cancel_data (void *data)
+{
+  OwnershipCancelData *d = data;
+
+  dbus_connection_unref (d->owner->conn);
+  bus_owner_unref (d->owner);
+  bus_service_unref (d->service);
+  
+  dbus_free (d);
+}
+
+static dbus_bool_t
+add_cancel_ownership_to_transaction (BusTransaction *transaction,
+                                     BusService     *service,
+                                     BusOwner       *owner)
+{
+  OwnershipCancelData *d;
+
+  d = dbus_new (OwnershipCancelData, 1);
+  if (d == NULL)
+    return FALSE;
+  
+  d->service = service;
+  d->owner = owner;
+
+  if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d,
+                                        free_ownership_cancel_data))
+    {
+      dbus_free (d);
+      return FALSE;
+    }
+
+  bus_service_ref (d->service);
+  bus_owner_ref (owner);
+  dbus_connection_ref (d->owner->conn);
+
+  return TRUE;
+}
+
+/* this function is self-cancelling if you cancel the transaction */
+dbus_bool_t
+bus_service_add_owner (BusService     *service,
+                       DBusConnection *connection,
+                       dbus_uint32_t  flags,
+                       BusTransaction *transaction,
+                       DBusError      *error)
+{
+  BusOwner *bus_owner;
+  DBusList *bus_owner_link;
+  
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  
+ /* Send service acquired message first, OOM will result
+  * in cancelling the transaction
+  */
+  if (service->owners == NULL)
+    {
+      if (!bus_driver_send_service_acquired (connection, service->name, transaction, error))
+        return FALSE;
+    }
+  
+  bus_owner_link = _bus_service_find_owner_link (service, connection);
+  
+  if (bus_owner_link == NULL)
+    {
+      bus_owner = bus_owner_new (service, connection, flags);
+      if (bus_owner == NULL)
+        {
+          BUS_SET_OOM (error);
+          return FALSE;
+        }
+
+      bus_owner_set_flags (bus_owner, flags);
+      if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL)
+        {
+          if (!_dbus_list_append (&service->owners,
+                                  bus_owner))
+            {
+              bus_owner_unref (bus_owner);
+              BUS_SET_OOM (error);
+              return FALSE;
+            }
+        }
+      else
+        {
+          if (!_dbus_list_insert_after (&service->owners,
+                                         _dbus_list_get_first_link (&service->owners),
+                                         bus_owner))
+            {
+              bus_owner_unref (bus_owner);
+              BUS_SET_OOM (error);
+              return FALSE;
+            }
+        }      
+    } 
+  else 
+    {
+      /* Update the link since we are already in the queue
+       * No need for operations that can produce OOM
+       */
+
+      bus_owner = (BusOwner *) bus_owner_link->data;
+      if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING)
+        {
+         DBusList *link;
+          _dbus_list_unlink (&service->owners, bus_owner_link);
+         link = _dbus_list_get_first_link (&service->owners);
+         _dbus_assert (link != NULL);
+         
+          _dbus_list_insert_after_link (&service->owners, link, bus_owner_link);
+        }
+      
+      bus_owner_set_flags (bus_owner, flags);
+      return TRUE;
+    }
+
+  if (!add_cancel_ownership_to_transaction (transaction,
+                                            service,
+                                            bus_owner))
+    {
+      bus_service_unlink_owner (service, bus_owner);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+typedef struct
+{
+  BusOwner       *owner;
+  BusService     *service;
+  BusOwner       *before_owner; /* restore to position before this connection in owners list */
+  DBusList       *owner_link;
+  DBusList       *service_link;
+  DBusPreallocatedHash *hash_entry;
+} OwnershipRestoreData;
+
+static void
+restore_ownership (void *data)
+{
+  OwnershipRestoreData *d = data;
+  DBusList *link;
+
+  _dbus_assert (d->service_link != NULL);
+  _dbus_assert (d->owner_link != NULL);
+  
+  if (d->service->owners == NULL)
+    {
+      _dbus_assert (d->hash_entry != NULL);
+      bus_service_relink (d->service, d->hash_entry);
+    }
+  else
+    {
+      _dbus_assert (d->hash_entry == NULL);
+    }
+  
+  /* We don't need to send messages notifying of these
+   * changes, since we're reverting something that was
+   * cancelled (effectively never really happened)
+   */
+  link = _dbus_list_get_first_link (&d->service->owners);
+  while (link != NULL)
+    {
+      if (link->data == d->before_owner)
+        break;
+
+      link = _dbus_list_get_next_link (&d->service->owners, link);
+    }
+  
+  _dbus_list_insert_before_link (&d->service->owners, link, d->owner_link);
+
+  /* Note that removing then restoring this changes the order in which
+   * ServiceDeleted messages are sent on destruction of the
+   * connection.  This should be OK as the only guarantee there is
+   * that the base service is destroyed last, and we never even
+   * tentatively remove the base service.
+   */
+  bus_connection_add_owned_service_link (d->owner->conn, d->service_link);
+  
+  d->hash_entry = NULL;
+  d->service_link = NULL;
+  d->owner_link = NULL;
+}
+
+static void
+free_ownership_restore_data (void *data)
+{
+  OwnershipRestoreData *d = data;
+
+  if (d->service_link)
+    _dbus_list_free_link (d->service_link);
+  if (d->owner_link)
+    _dbus_list_free_link (d->owner_link);
+  if (d->hash_entry)
+    _dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash,
+                                              d->hash_entry);
+
+  dbus_connection_unref (d->owner->conn);
+  bus_owner_unref (d->owner);
+  bus_service_unref (d->service);
+  
+  dbus_free (d);
+}
+
+static dbus_bool_t
+add_restore_ownership_to_transaction (BusTransaction *transaction,
+                                      BusService     *service,
+                                      BusOwner       *owner)
+{
+  OwnershipRestoreData *d;
+  DBusList *link;
+
+  d = dbus_new (OwnershipRestoreData, 1);
+  if (d == NULL)
+    return FALSE;
+  
+  d->service = service;
+  d->owner = owner;
+  d->service_link = _dbus_list_alloc_link (service);
+  d->owner_link = _dbus_list_alloc_link (owner);
+  d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash);
+  
+  bus_service_ref (d->service);
+  bus_owner_ref (d->owner);
+  dbus_connection_ref (d->owner->conn);
+
+  d->before_owner = NULL;
+  link = _dbus_list_get_first_link (&service->owners);
+  while (link != NULL)
+    {
+      if (link->data == owner)
+        {
+          link = _dbus_list_get_next_link (&service->owners, link);
+
+          if (link)
+            d->before_owner = link->data;
+
+          break;
+        }
+      
+      link = _dbus_list_get_next_link (&service->owners, link);
+    }
+  
+  if (d->service_link == NULL ||
+      d->owner_link == NULL ||
+      d->hash_entry == NULL ||
+      !bus_transaction_add_cancel_hook (transaction, restore_ownership, d,
+                                        free_ownership_restore_data))
+    {
+      free_ownership_restore_data (d);
+      return FALSE;
+    }
+  
+  return TRUE;
+}
+
+dbus_bool_t
+bus_service_swap_owner (BusService     *service,
+                        DBusConnection *connection,
+                        BusTransaction *transaction,
+                        DBusError      *error)
+{
+  DBusList *swap_link;
+  BusOwner *primary_owner;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  /* We send out notifications before we do any work we
+   * might have to undo if the notification-sending failed
+   */
+  
+  /* Send service lost message */
+  primary_owner = bus_service_get_primary_owner (service);
+  if (primary_owner == NULL || primary_owner->conn != connection)
+    _dbus_assert_not_reached ("Tried to swap a non primary owner");
+
+    
+  if (!bus_driver_send_service_lost (connection, service->name,
+                                     transaction, error))
+    return FALSE;
+
+  if (service->owners == NULL)
+    {
+      _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners");
+    }
+  else if (_dbus_list_length_is_one (&service->owners))
+    {
+      _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue");
+    }
+  else
+    {
+      DBusList *link;
+      BusOwner *new_owner;
+      DBusConnection *new_owner_conn;
+      link = _dbus_list_get_first_link (&service->owners);
+      _dbus_assert (link != NULL);
+      link = _dbus_list_get_next_link (&service->owners, link);
+      _dbus_assert (link != NULL);
+
+      new_owner = (BusOwner *)link->data;
+      new_owner_conn = new_owner->conn;
+
+      if (!bus_driver_send_service_owner_changed (service->name,
+                                                 bus_connection_get_name (connection),
+                                                 bus_connection_get_name (new_owner_conn),
+                                                 transaction, error))
+        return FALSE;
+
+      /* This will be our new owner */
+      if (!bus_driver_send_service_acquired (new_owner_conn,
+                                             service->name,
+                                             transaction,
+                                             error))
+        return FALSE;
+    }
+
+  if (!add_restore_ownership_to_transaction (transaction, service, primary_owner))
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  /* unlink the primary and make it the second link */
+  swap_link = _dbus_list_get_first_link (&service->owners);
+  _dbus_list_unlink (&service->owners, swap_link);
+
+  _dbus_list_insert_after_link (&service->owners,
+                                _dbus_list_get_first_link (&service->owners),
+                               swap_link);
+
+  return TRUE;
+}
+
+/* this function is self-cancelling if you cancel the transaction */
+dbus_bool_t
+bus_service_remove_owner (BusService     *service,
+                          DBusConnection *connection,
+                          BusTransaction *transaction,
+                          DBusError      *error)
+{
+  BusOwner *primary_owner;
+  
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  
+  /* We send out notifications before we do any work we
+   * might have to undo if the notification-sending failed
+   */
+  
+  /* Send service lost message */
+  primary_owner = bus_service_get_primary_owner (service);
+  if (primary_owner != NULL && primary_owner->conn == connection)
+    {
+      if (!bus_driver_send_service_lost (connection, service->name,
+                                         transaction, error))
+        return FALSE;
+    }
+  else
+    {
+      /* if we are not the primary owner then just remove us from the queue */
+      DBusList *link;
+      BusOwner *temp_owner;
+
+      link = _bus_service_find_owner_link (service, connection);
+      _dbus_list_unlink (&service->owners, link);
+      temp_owner = (BusOwner *)link->data;
+      bus_owner_unref (temp_owner); 
+      _dbus_list_free_link (link);
+
+      return TRUE; 
+    }
+
+  if (service->owners == NULL)
+    {
+      _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners");
+    }
+  else if (_dbus_list_length_is_one (&service->owners))
+    {
+      if (!bus_driver_send_service_owner_changed (service->name,
+                                                 bus_connection_get_name (connection),
+                                                 NULL,
+                                                 transaction, error))
+        return FALSE;
+    }
+  else
+    {
+      DBusList *link;
+      BusOwner *new_owner;
+      DBusConnection *new_owner_conn;
+      link = _dbus_list_get_first_link (&service->owners);
+      _dbus_assert (link != NULL);
+      link = _dbus_list_get_next_link (&service->owners, link);
+      _dbus_assert (link != NULL);
+
+      new_owner = (BusOwner *)link->data;
+      new_owner_conn = new_owner->conn;
+
+      if (!bus_driver_send_service_owner_changed (service->name,
+                                                 bus_connection_get_name (connection),
+                                                 bus_connection_get_name (new_owner_conn),
+                                                 transaction, error))
+        return FALSE;
+
+      /* This will be our new owner */
+      if (!bus_driver_send_service_acquired (new_owner_conn,
+                                             service->name,
+                                             transaction,
+                                             error))
+        return FALSE;
+    }
+
+  if (!add_restore_ownership_to_transaction (transaction, service, primary_owner))
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+  bus_service_unlink_owner (service, primary_owner);
+
+  if (service->owners == NULL)
+    bus_service_unlink (service);
+
+  return TRUE;
+}
+
+BusService *
+bus_service_ref (BusService *service)
+{
+  _dbus_assert (service->refcount > 0);
+  
+  service->refcount += 1;
+
+  return service;
+}
+
+void
+bus_service_unref (BusService *service)
+{
+  _dbus_assert (service->refcount > 0);
+  
+  service->refcount -= 1;
+
+  if (service->refcount == 0)
+    {
+      _dbus_assert (service->owners == NULL);
+      
+      dbus_free (service->name);
+      _dbus_mem_pool_dealloc (service->registry->service_pool, service);
+    }
+}
+
+DBusConnection *
+bus_service_get_primary_owners_connection (BusService *service)
+{
+  BusOwner *owner;
+#ifdef ENABLE_KDBUS_TRANSPORT
+  char unique_name[(unsigned int)(snprintf((char*)NULL, 0, "%llu", ULLONG_MAX) + sizeof(":1."))];
+#endif
+
+  owner = bus_service_get_primary_owner (service);
+
+#ifdef ENABLE_KDBUS_TRANSPORT
+  if(!owner)
+    return NULL;
+  if(bus_context_is_kdbus(service->registry->context))
+  {
+    if(kdbus_get_name_owner(owner->conn, bus_service_get_name(service), unique_name) < 0)
+      return NULL;
+    return _bus_service_find_owner_connection(service, unique_name);  //bus_connections_find_conn_by_name would be safer? but slower
+  }
+  else
+    return owner->conn;
+#else
+  if (owner != NULL)
+    return owner->conn;
+  else
+    return NULL;
+#endif
+}
+
+BusOwner*
+bus_service_get_primary_owner (BusService *service)
+{
+  return _dbus_list_get_first (&service->owners);
+}
+
+const char*
+bus_service_get_name (BusService *service)
+{
+  return service->name;
+}
+
+dbus_bool_t
+bus_service_get_allow_replacement (BusService *service)
+{
+  BusOwner *owner;
+  DBusList *link;
+  _dbus_assert (service->owners != NULL);
+
+  link = _dbus_list_get_first_link (&service->owners);
+  owner = (BusOwner *) link->data;
+
+  return owner->allow_replacement;
+}
+
+#ifdef ENABLE_KDBUS_TRANSPORT
+dbus_bool_t
+bus_service_get_is_kdbus_starter (BusService *service)
+{
+  BusOwner *owner;
+  DBusList *link;
+
+  _dbus_assert (service->owners != NULL);
+
+  link = _dbus_list_get_first_link (&service->owners);
+  owner = (BusOwner *) link->data;
+
+  return owner->is_kdbus_starter;
+}
+#endif
+
+dbus_bool_t
+bus_service_has_owner (BusService     *service,
+                      DBusConnection *connection)
+{
+  DBusList *link;
+
+  link = _bus_service_find_owner_link (service, connection);
+  if (link == NULL)
+    return FALSE;
+  else
+    return TRUE;
+}
+
+dbus_bool_t 
+bus_service_list_queued_owners (BusService *service,
+                                DBusList  **return_list,
+                                DBusError  *error)
+{
+  DBusList *link;
+
+  _dbus_assert (*return_list == NULL);
+
+  link = _dbus_list_get_first_link (&service->owners);
+  _dbus_assert (link != NULL);
+  
+  while (link != NULL)
+    {
+      BusOwner *owner;
+      const char *uname;
+
+      owner = (BusOwner *) link->data;
+      uname = bus_connection_get_name (owner->conn);
+
+#ifdef ENABLE_KDBUS_TRANSPORT
+      if(!owner->is_kdbus_starter)
+#endif
+          if (!_dbus_list_append (return_list, (char *)uname))
+              goto oom;
+
+      link = _dbus_list_get_next_link (&service->owners, link);
+    }
+  
+  return TRUE;
+  
+ oom:
+  _dbus_list_clear (return_list);
+  BUS_SET_OOM (error);
+  return FALSE;
 }