Home | History | Annotate | Download | only in bus
      1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
      2 /* services.c  Service management
      3  *
      4  * Copyright (C) 2003  Red Hat, Inc.
      5  * Copyright (C) 2003  CodeFactory AB
      6  *
      7  * Licensed under the Academic Free License version 2.1
      8  *
      9  * This program is free software; you can redistribute it and/or modify
     10  * it under the terms of the GNU General Public License as published by
     11  * the Free Software Foundation; either version 2 of the License, or
     12  * (at your option) any later version.
     13  *
     14  * This program is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  * GNU General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU General Public License
     20  * along with this program; if not, write to the Free Software
     21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     22  *
     23  */
     24 
     25 #include <config.h>
     26 #include <dbus/dbus-hash.h>
     27 #include <dbus/dbus-list.h>
     28 #include <dbus/dbus-mempool.h>
     29 #include <dbus/dbus-marshal-validate.h>
     30 
     31 #include "driver.h"
     32 #include "services.h"
     33 #include "connection.h"
     34 #include "utils.h"
     35 #include "activation.h"
     36 #include "policy.h"
     37 #include "bus.h"
     38 #include "selinux.h"
     39 
     40 struct BusService
     41 {
     42   int refcount;
     43 
     44   BusRegistry *registry;
     45   char *name;
     46   DBusList *owners;
     47 };
     48 
     49 struct BusOwner
     50 {
     51   int refcount;
     52 
     53   BusService *service;
     54   DBusConnection *conn;
     55 
     56   unsigned int allow_replacement : 1;
     57   unsigned int do_not_queue : 1;
     58 };
     59 
     60 struct BusRegistry
     61 {
     62   int refcount;
     63 
     64   BusContext *context;
     65 
     66   DBusHashTable *service_hash;
     67   DBusMemPool   *service_pool;
     68   DBusMemPool   *owner_pool;
     69 
     70   DBusHashTable *service_sid_table;
     71 };
     72 
     73 BusRegistry*
     74 bus_registry_new (BusContext *context)
     75 {
     76   BusRegistry *registry;
     77 
     78   registry = dbus_new0 (BusRegistry, 1);
     79   if (registry == NULL)
     80     return NULL;
     81 
     82   registry->refcount = 1;
     83   registry->context = context;
     84 
     85   registry->service_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
     86                                                  NULL, NULL);
     87   if (registry->service_hash == NULL)
     88     goto failed;
     89 
     90   registry->service_pool = _dbus_mem_pool_new (sizeof (BusService),
     91                                                TRUE);
     92 
     93   if (registry->service_pool == NULL)
     94     goto failed;
     95 
     96   registry->owner_pool = _dbus_mem_pool_new (sizeof (BusOwner),
     97                                              TRUE);
     98 
     99   if (registry->owner_pool == NULL)
    100     goto failed;
    101 
    102   registry->service_sid_table = NULL;
    103 
    104   return registry;
    105 
    106  failed:
    107   bus_registry_unref (registry);
    108   return NULL;
    109 }
    110 
    111 BusRegistry *
    112 bus_registry_ref (BusRegistry *registry)
    113 {
    114   _dbus_assert (registry->refcount > 0);
    115   registry->refcount += 1;
    116 
    117   return registry;
    118 }
    119 
    120 void
    121 bus_registry_unref  (BusRegistry *registry)
    122 {
    123   _dbus_assert (registry->refcount > 0);
    124   registry->refcount -= 1;
    125 
    126   if (registry->refcount == 0)
    127     {
    128       if (registry->service_hash)
    129         _dbus_hash_table_unref (registry->service_hash);
    130       if (registry->service_pool)
    131         _dbus_mem_pool_free (registry->service_pool);
    132       if (registry->owner_pool)
    133         _dbus_mem_pool_free (registry->owner_pool);
    134       if (registry->service_sid_table)
    135         _dbus_hash_table_unref (registry->service_sid_table);
    136 
    137       dbus_free (registry);
    138     }
    139 }
    140 
    141 BusService*
    142 bus_registry_lookup (BusRegistry      *registry,
    143                      const DBusString *service_name)
    144 {
    145   BusService *service;
    146 
    147   service = _dbus_hash_table_lookup_string (registry->service_hash,
    148                                             _dbus_string_get_const_data (service_name));
    149 
    150   return service;
    151 }
    152 
    153 static DBusList *
    154 _bus_service_find_owner_link (BusService *service,
    155                               DBusConnection *connection)
    156 {
    157   DBusList *link;
    158 
    159   link = _dbus_list_get_first_link (&service->owners);
    160 
    161   while (link != NULL)
    162     {
    163       BusOwner *bus_owner;
    164 
    165       bus_owner = (BusOwner *) link->data;
    166       if (bus_owner->conn == connection)
    167         break;
    168 
    169       link = _dbus_list_get_next_link (&service->owners, link);
    170     }
    171 
    172   return link;
    173 }
    174 
    175 static void
    176 bus_owner_set_flags (BusOwner *owner,
    177                      dbus_uint32_t flags)
    178 {
    179    owner->allow_replacement =
    180         (flags & DBUS_NAME_FLAG_ALLOW_REPLACEMENT) != FALSE;
    181 
    182    owner->do_not_queue =
    183         (flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) != FALSE;
    184 }
    185 
    186 static BusOwner *
    187 bus_owner_new (BusService *service,
    188                DBusConnection *conn,
    189 	       dbus_uint32_t flags)
    190 {
    191   BusOwner *result;
    192 
    193   result = _dbus_mem_pool_alloc (service->registry->owner_pool);
    194   if (result != NULL)
    195     {
    196       result->refcount = 1;
    197       /* don't ref the connection because we don't want
    198          to block the connection from going away.
    199          transactions take care of reffing the connection
    200          but we need to use refcounting on the owner
    201          so that the owner does not get freed before
    202          we can deref the connection in the transaction
    203        */
    204       result->conn = conn;
    205       result->service = service;
    206 
    207       if (!bus_connection_add_owned_service (conn, service))
    208         {
    209           _dbus_mem_pool_dealloc (service->registry->owner_pool, result);
    210           return NULL;
    211         }
    212 
    213       bus_owner_set_flags (result, flags);
    214     }
    215   return result;
    216 }
    217 
    218 static BusOwner *
    219 bus_owner_ref (BusOwner *owner)
    220 {
    221   _dbus_assert (owner->refcount > 0);
    222   owner->refcount += 1;
    223 
    224   return owner;
    225 }
    226 
    227 static void
    228 bus_owner_unref  (BusOwner *owner)
    229 {
    230   _dbus_assert (owner->refcount > 0);
    231   owner->refcount -= 1;
    232 
    233   if (owner->refcount == 0)
    234     {
    235       bus_connection_remove_owned_service (owner->conn, owner->service);
    236       _dbus_mem_pool_dealloc (owner->service->registry->owner_pool, owner);
    237     }
    238 }
    239 
    240 BusService*
    241 bus_registry_ensure (BusRegistry               *registry,
    242                      const DBusString          *service_name,
    243                      DBusConnection            *owner_connection_if_created,
    244                      dbus_uint32_t              flags,
    245                      BusTransaction            *transaction,
    246                      DBusError                 *error)
    247 {
    248   BusService *service;
    249 
    250   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    251 
    252   _dbus_assert (owner_connection_if_created != NULL);
    253   _dbus_assert (transaction != NULL);
    254 
    255   service = _dbus_hash_table_lookup_string (registry->service_hash,
    256                                             _dbus_string_get_const_data (service_name));
    257   if (service != NULL)
    258     return service;
    259 
    260   service = _dbus_mem_pool_alloc (registry->service_pool);
    261   if (service == NULL)
    262     {
    263       BUS_SET_OOM (error);
    264       return NULL;
    265     }
    266 
    267   service->registry = registry;
    268   service->refcount = 1;
    269 
    270   _dbus_verbose ("copying string %p '%s' to service->name\n",
    271                  service_name, _dbus_string_get_const_data (service_name));
    272   if (!_dbus_string_copy_data (service_name, &service->name))
    273     {
    274       _dbus_mem_pool_dealloc (registry->service_pool, service);
    275       BUS_SET_OOM (error);
    276       return NULL;
    277     }
    278   _dbus_verbose ("copied string %p '%s' to '%s'\n",
    279                  service_name, _dbus_string_get_const_data (service_name),
    280                  service->name);
    281 
    282   if (!bus_driver_send_service_owner_changed (service->name,
    283 					      NULL,
    284 					      bus_connection_get_name (owner_connection_if_created),
    285 					      transaction, error))
    286     {
    287       bus_service_unref (service);
    288       return NULL;
    289     }
    290 
    291   if (!bus_activation_service_created (bus_context_get_activation (registry->context),
    292 				       service->name, transaction, error))
    293     {
    294       bus_service_unref (service);
    295       return NULL;
    296     }
    297 
    298   if (!bus_service_add_owner (service, owner_connection_if_created, flags,
    299                                               transaction, error))
    300     {
    301       bus_service_unref (service);
    302       return NULL;
    303     }
    304 
    305   if (!_dbus_hash_table_insert_string (registry->service_hash,
    306                                        service->name,
    307                                        service))
    308     {
    309       /* The add_owner gets reverted on transaction cancel */
    310       BUS_SET_OOM (error);
    311       return NULL;
    312     }
    313 
    314   return service;
    315 }
    316 
    317 void
    318 bus_registry_foreach (BusRegistry               *registry,
    319                       BusServiceForeachFunction  function,
    320                       void                      *data)
    321 {
    322   DBusHashIter iter;
    323 
    324   _dbus_hash_iter_init (registry->service_hash, &iter);
    325   while (_dbus_hash_iter_next (&iter))
    326     {
    327       BusService *service = _dbus_hash_iter_get_value (&iter);
    328 
    329       (* function) (service, data);
    330     }
    331 }
    332 
    333 dbus_bool_t
    334 bus_registry_list_services (BusRegistry *registry,
    335                             char      ***listp,
    336                             int         *array_len)
    337 {
    338   int i, j, len;
    339   char **retval;
    340   DBusHashIter iter;
    341 
    342   len = _dbus_hash_table_get_n_entries (registry->service_hash);
    343   retval = dbus_new (char *, len + 1);
    344 
    345   if (retval == NULL)
    346     return FALSE;
    347 
    348   _dbus_hash_iter_init (registry->service_hash, &iter);
    349   i = 0;
    350   while (_dbus_hash_iter_next (&iter))
    351     {
    352       BusService *service = _dbus_hash_iter_get_value (&iter);
    353 
    354       retval[i] = _dbus_strdup (service->name);
    355       if (retval[i] == NULL)
    356 	goto error;
    357 
    358       i++;
    359     }
    360 
    361   retval[i] = NULL;
    362 
    363   if (array_len)
    364     *array_len = len;
    365 
    366   *listp = retval;
    367   return TRUE;
    368 
    369  error:
    370   for (j = 0; j < i; j++)
    371     dbus_free (retval[i]);
    372   dbus_free (retval);
    373 
    374   return FALSE;
    375 }
    376 
    377 dbus_bool_t
    378 bus_registry_acquire_service (BusRegistry      *registry,
    379                               DBusConnection   *connection,
    380                               const DBusString *service_name,
    381                               dbus_uint32_t     flags,
    382                               dbus_uint32_t    *result,
    383                               BusTransaction   *transaction,
    384                               DBusError        *error)
    385 {
    386   dbus_bool_t retval;
    387   DBusConnection *old_owner_conn;
    388   DBusConnection *current_owner_conn;
    389   BusClientPolicy *policy;
    390   BusService *service;
    391   BusActivation  *activation;
    392   BusSELinuxID *sid;
    393   BusOwner *primary_owner;
    394 
    395   retval = FALSE;
    396 
    397   if (!_dbus_validate_bus_name (service_name, 0,
    398                                 _dbus_string_get_length (service_name)))
    399     {
    400       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
    401                       "Requested bus name \"%s\" is not valid",
    402                       _dbus_string_get_const_data (service_name));
    403 
    404       _dbus_verbose ("Attempt to acquire invalid service name\n");
    405 
    406       goto out;
    407     }
    408 
    409   if (_dbus_string_get_byte (service_name, 0) == ':')
    410     {
    411       /* Not allowed; only base services can start with ':' */
    412       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
    413                       "Cannot acquire a service starting with ':' such as \"%s\"",
    414                       _dbus_string_get_const_data (service_name));
    415 
    416       _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"",
    417                      _dbus_string_get_const_data (service_name));
    418 
    419       goto out;
    420     }
    421 
    422   if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS))
    423     {
    424       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
    425                       "Connection \"%s\" is not allowed to own the service \"%s\"because "
    426                       "it is reserved for D-Bus' use only",
    427                       bus_connection_is_active (connection) ?
    428                       bus_connection_get_name (connection) :
    429                       "(inactive)",
    430                       DBUS_SERVICE_DBUS);
    431       goto out;
    432     }
    433 
    434   policy = bus_connection_get_policy (connection);
    435   _dbus_assert (policy != NULL);
    436 
    437   /* Note that if sid is #NULL then the bus's own context gets used
    438    * in bus_connection_selinux_allows_acquire_service()
    439    */
    440   sid = bus_selinux_id_table_lookup (registry->service_sid_table,
    441                                      service_name);
    442 
    443   if (!bus_selinux_allows_acquire_service (connection, sid,
    444 					   _dbus_string_get_const_data (service_name), error))
    445     {
    446 
    447       if (dbus_error_is_set (error) &&
    448 	  dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY))
    449 	{
    450 	  goto out;
    451 	}
    452 
    453       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
    454                       "Connection \"%s\" is not allowed to own the service \"%s\" due "
    455                       "to SELinux policy",
    456                       bus_connection_is_active (connection) ?
    457                       bus_connection_get_name (connection) :
    458                       "(inactive)",
    459                       _dbus_string_get_const_data (service_name));
    460       goto out;
    461     }
    462 
    463   if (!bus_client_policy_check_can_own (policy, connection,
    464                                         service_name))
    465     {
    466       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
    467                       "Connection \"%s\" is not allowed to own the service \"%s\" due "
    468                       "to security policies in the configuration file",
    469                       bus_connection_is_active (connection) ?
    470                       bus_connection_get_name (connection) :
    471                       "(inactive)",
    472                       _dbus_string_get_const_data (service_name));
    473       goto out;
    474     }
    475 
    476   if (bus_connection_get_n_services_owned (connection) >=
    477       bus_context_get_max_services_per_connection (registry->context))
    478     {
    479       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
    480                       "Connection \"%s\" is not allowed to own more services "
    481                       "(increase limits in configuration file if required)",
    482                       bus_connection_is_active (connection) ?
    483                       bus_connection_get_name (connection) :
    484                       "(inactive)");
    485       goto out;
    486     }
    487 
    488   service = bus_registry_lookup (registry, service_name);
    489 
    490   if (service != NULL)
    491     {
    492       primary_owner = bus_service_get_primary_owner (service);
    493       if (primary_owner != NULL)
    494         old_owner_conn = primary_owner->conn;
    495       else
    496         old_owner_conn = NULL;
    497     }
    498   else
    499     old_owner_conn = NULL;
    500 
    501   if (service == NULL)
    502     {
    503       service = bus_registry_ensure (registry,
    504                                      service_name, connection, flags,
    505                                      transaction, error);
    506       if (service == NULL)
    507         goto out;
    508     }
    509 
    510   primary_owner = bus_service_get_primary_owner (service);
    511   if (primary_owner == NULL)
    512     goto out;
    513 
    514   current_owner_conn = primary_owner->conn;
    515 
    516   if (old_owner_conn == NULL)
    517     {
    518       _dbus_assert (current_owner_conn == connection);
    519 
    520       *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
    521     }
    522   else if (old_owner_conn == connection)
    523     {
    524       bus_owner_set_flags (primary_owner, flags);
    525       *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
    526     }
    527   else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
    528            !(bus_service_get_allow_replacement (service))) ||
    529 	   ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
    530            !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING)))
    531     {
    532       DBusList *link;
    533       BusOwner *temp_owner;
    534     /* Since we can't be queued if we are already in the queue
    535        remove us */
    536 
    537       link = _bus_service_find_owner_link (service, connection);
    538       if (link != NULL)
    539         {
    540           _dbus_list_unlink (&service->owners, link);
    541           temp_owner = (BusOwner *)link->data;
    542           bus_owner_unref (temp_owner);
    543           _dbus_list_free_link (link);
    544         }
    545 
    546       *result = DBUS_REQUEST_NAME_REPLY_EXISTS;
    547     }
    548   else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
    549            (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) ||
    550 	    !(bus_service_get_allow_replacement (service))))
    551     {
    552       /* Queue the connection */
    553       if (!bus_service_add_owner (service, connection,
    554                                   flags,
    555                                   transaction, error))
    556         goto out;
    557 
    558       *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE;
    559     }
    560   else
    561     {
    562       /* Replace the current owner */
    563 
    564       /* We enqueue the new owner and remove the first one because
    565        * that will cause NameAcquired and NameLost messages to
    566        * be sent.
    567        */
    568 
    569       if (!bus_service_add_owner (service, connection,
    570                                   flags,
    571                                   transaction, error))
    572         goto out;
    573 
    574       if (primary_owner->do_not_queue)
    575         {
    576           if (!bus_service_remove_owner (service, old_owner_conn,
    577                                          transaction, error))
    578             goto out;
    579         }
    580       else
    581         {
    582           if (!bus_service_swap_owner (service, old_owner_conn,
    583                                        transaction, error))
    584             goto out;
    585         }
    586 
    587 
    588       _dbus_assert (connection == bus_service_get_primary_owner (service)->conn);
    589       *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
    590     }
    591 
    592   activation = bus_context_get_activation (registry->context);
    593   retval = bus_activation_send_pending_auto_activation_messages (activation,
    594 								 service,
    595 								 transaction,
    596 								 error);
    597 
    598  out:
    599   return retval;
    600 }
    601 
    602 dbus_bool_t
    603 bus_registry_release_service (BusRegistry      *registry,
    604                               DBusConnection   *connection,
    605                               const DBusString *service_name,
    606                               dbus_uint32_t    *result,
    607                               BusTransaction   *transaction,
    608                               DBusError        *error)
    609 {
    610   dbus_bool_t retval;
    611   BusService *service;
    612 
    613   retval = FALSE;
    614 
    615   if (!_dbus_validate_bus_name (service_name, 0,
    616                                 _dbus_string_get_length (service_name)))
    617     {
    618       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
    619                       "Given bus name \"%s\" is not valid",
    620                       _dbus_string_get_const_data (service_name));
    621 
    622       _dbus_verbose ("Attempt to release invalid service name\n");
    623 
    624       goto out;
    625     }
    626 
    627   if (_dbus_string_get_byte (service_name, 0) == ':')
    628     {
    629       /* Not allowed; the base service name cannot be created or released */
    630       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
    631                       "Cannot release a service starting with ':' such as \"%s\"",
    632                       _dbus_string_get_const_data (service_name));
    633 
    634       _dbus_verbose ("Attempt to release invalid base service name \"%s\"",
    635                      _dbus_string_get_const_data (service_name));
    636 
    637       goto out;
    638     }
    639 
    640    if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS))
    641     {
    642       /* Not allowed; the base service name cannot be created or released */
    643       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
    644                       "Cannot release the %s service because it is owned by the bus",
    645                      DBUS_SERVICE_DBUS);
    646 
    647       _dbus_verbose ("Attempt to release service name \"%s\"",
    648                      DBUS_SERVICE_DBUS);
    649 
    650       goto out;
    651     }
    652 
    653   service = bus_registry_lookup (registry, service_name);
    654 
    655   if (service == NULL)
    656     {
    657       *result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT;
    658     }
    659   else if (!bus_service_has_owner (service, connection))
    660     {
    661       *result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER;
    662     }
    663   else
    664     {
    665       if (!bus_service_remove_owner (service, connection,
    666                                      transaction, error))
    667         goto out;
    668 
    669       _dbus_assert (!bus_service_has_owner (service, connection));
    670       *result = DBUS_RELEASE_NAME_REPLY_RELEASED;
    671     }
    672 
    673   retval = TRUE;
    674 
    675  out:
    676   return retval;
    677 }
    678 
    679 dbus_bool_t
    680 bus_registry_set_service_context_table (BusRegistry   *registry,
    681 					DBusHashTable *table)
    682 {
    683   DBusHashTable *new_table;
    684   DBusHashIter iter;
    685 
    686   new_table = bus_selinux_id_table_new ();
    687   if (!new_table)
    688     return FALSE;
    689 
    690   _dbus_hash_iter_init (table, &iter);
    691   while (_dbus_hash_iter_next (&iter))
    692     {
    693       const char *service = _dbus_hash_iter_get_string_key (&iter);
    694       const char *context = _dbus_hash_iter_get_value (&iter);
    695 
    696       if (!bus_selinux_id_table_insert (new_table,
    697 					service,
    698 					context))
    699 	return FALSE;
    700     }
    701 
    702   if (registry->service_sid_table)
    703     _dbus_hash_table_unref (registry->service_sid_table);
    704   registry->service_sid_table = new_table;
    705   return TRUE;
    706 }
    707 
    708 static void
    709 bus_service_unlink_owner (BusService      *service,
    710                           BusOwner        *owner)
    711 {
    712   _dbus_list_remove_last (&service->owners, owner);
    713   bus_owner_unref (owner);
    714 }
    715 
    716 static void
    717 bus_service_unlink (BusService *service)
    718 {
    719   _dbus_assert (service->owners == NULL);
    720 
    721   /* the service may not be in the hash, if
    722    * the failure causing transaction cancel
    723    * was in the right place, but that's OK
    724    */
    725   _dbus_hash_table_remove_string (service->registry->service_hash,
    726                                   service->name);
    727 
    728   bus_service_unref (service);
    729 }
    730 
    731 static void
    732 bus_service_relink (BusService           *service,
    733                     DBusPreallocatedHash *preallocated)
    734 {
    735   _dbus_assert (service->owners == NULL);
    736   _dbus_assert (preallocated != NULL);
    737 
    738   _dbus_hash_table_insert_string_preallocated (service->registry->service_hash,
    739                                                preallocated,
    740                                                service->name,
    741                                                service);
    742 
    743   bus_service_ref (service);
    744 }
    745 
    746 /**
    747  * Data used to represent an ownership cancellation in
    748  * a bus transaction.
    749  */
    750 typedef struct
    751 {
    752   BusOwner *owner;            /**< the owner */
    753   BusService *service;        /**< service to cancel ownership of */
    754 } OwnershipCancelData;
    755 
    756 static void
    757 cancel_ownership (void *data)
    758 {
    759   OwnershipCancelData *d = data;
    760 
    761   /* We don't need to send messages notifying of these
    762    * changes, since we're reverting something that was
    763    * cancelled (effectively never really happened)
    764    */
    765   bus_service_unlink_owner (d->service, d->owner);
    766 
    767   if (d->service->owners == NULL)
    768     bus_service_unlink (d->service);
    769 }
    770 
    771 static void
    772 free_ownership_cancel_data (void *data)
    773 {
    774   OwnershipCancelData *d = data;
    775 
    776   dbus_connection_unref (d->owner->conn);
    777   bus_owner_unref (d->owner);
    778   bus_service_unref (d->service);
    779 
    780   dbus_free (d);
    781 }
    782 
    783 static dbus_bool_t
    784 add_cancel_ownership_to_transaction (BusTransaction *transaction,
    785                                      BusService     *service,
    786                                      BusOwner       *owner)
    787 {
    788   OwnershipCancelData *d;
    789 
    790   d = dbus_new (OwnershipCancelData, 1);
    791   if (d == NULL)
    792     return FALSE;
    793 
    794   d->service = service;
    795   d->owner = owner;
    796 
    797   if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d,
    798                                         free_ownership_cancel_data))
    799     {
    800       dbus_free (d);
    801       return FALSE;
    802     }
    803 
    804   bus_service_ref (d->service);
    805   bus_owner_ref (owner);
    806   dbus_connection_ref (d->owner->conn);
    807 
    808   return TRUE;
    809 }
    810 
    811 /* this function is self-cancelling if you cancel the transaction */
    812 dbus_bool_t
    813 bus_service_add_owner (BusService     *service,
    814                        DBusConnection *connection,
    815                        dbus_uint32_t  flags,
    816                        BusTransaction *transaction,
    817                        DBusError      *error)
    818 {
    819   BusOwner *bus_owner;
    820   DBusList *bus_owner_link;
    821 
    822   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    823 
    824  /* Send service acquired message first, OOM will result
    825   * in cancelling the transaction
    826   */
    827   if (service->owners == NULL)
    828     {
    829       if (!bus_driver_send_service_acquired (connection, service->name, transaction, error))
    830         return FALSE;
    831     }
    832 
    833   bus_owner_link = _bus_service_find_owner_link (service, connection);
    834 
    835   if (bus_owner_link == NULL)
    836     {
    837       bus_owner = bus_owner_new (service, connection, flags);
    838       if (bus_owner == NULL)
    839         {
    840           BUS_SET_OOM (error);
    841           return FALSE;
    842         }
    843 
    844       bus_owner_set_flags (bus_owner, flags);
    845       if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL)
    846         {
    847           if (!_dbus_list_append (&service->owners,
    848                                   bus_owner))
    849             {
    850               bus_owner_unref (bus_owner);
    851               BUS_SET_OOM (error);
    852               return FALSE;
    853             }
    854         }
    855       else
    856         {
    857           if (!_dbus_list_insert_after (&service->owners,
    858                                          _dbus_list_get_first_link (&service->owners),
    859                                          bus_owner))
    860             {
    861               bus_owner_unref (bus_owner);
    862               BUS_SET_OOM (error);
    863               return FALSE;
    864             }
    865         }
    866     }
    867   else
    868     {
    869       /* Update the link since we are already in the queue
    870        * No need for operations that can produce OOM
    871        */
    872 
    873       bus_owner = (BusOwner *) bus_owner_link->data;
    874       if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING)
    875         {
    876 	  DBusList *link;
    877           _dbus_list_unlink (&service->owners, bus_owner_link);
    878 	  link = _dbus_list_get_first_link (&service->owners);
    879 	  _dbus_assert (link != NULL);
    880 
    881           _dbus_list_insert_after_link (&service->owners, link, bus_owner_link);
    882         }
    883 
    884       bus_owner_set_flags (bus_owner, flags);
    885       return TRUE;
    886     }
    887 
    888   if (!add_cancel_ownership_to_transaction (transaction,
    889                                             service,
    890                                             bus_owner))
    891     {
    892       bus_service_unlink_owner (service, bus_owner);
    893       BUS_SET_OOM (error);
    894       return FALSE;
    895     }
    896 
    897   return TRUE;
    898 }
    899 
    900 typedef struct
    901 {
    902   BusOwner       *owner;
    903   BusService     *service;
    904   BusOwner       *before_owner; /* restore to position before this connection in owners list */
    905   DBusList       *owner_link;
    906   DBusList       *service_link;
    907   DBusPreallocatedHash *hash_entry;
    908 } OwnershipRestoreData;
    909 
    910 static void
    911 restore_ownership (void *data)
    912 {
    913   OwnershipRestoreData *d = data;
    914   DBusList *link;
    915 
    916   _dbus_assert (d->service_link != NULL);
    917   _dbus_assert (d->owner_link != NULL);
    918 
    919   if (d->service->owners == NULL)
    920     {
    921       _dbus_assert (d->hash_entry != NULL);
    922       bus_service_relink (d->service, d->hash_entry);
    923     }
    924   else
    925     {
    926       _dbus_assert (d->hash_entry == NULL);
    927     }
    928 
    929   /* We don't need to send messages notifying of these
    930    * changes, since we're reverting something that was
    931    * cancelled (effectively never really happened)
    932    */
    933   link = _dbus_list_get_first_link (&d->service->owners);
    934   while (link != NULL)
    935     {
    936       if (link->data == d->before_owner)
    937         break;
    938 
    939       link = _dbus_list_get_next_link (&d->service->owners, link);
    940     }
    941 
    942   _dbus_list_insert_before_link (&d->service->owners, link, d->owner_link);
    943 
    944   /* Note that removing then restoring this changes the order in which
    945    * ServiceDeleted messages are sent on destruction of the
    946    * connection.  This should be OK as the only guarantee there is
    947    * that the base service is destroyed last, and we never even
    948    * tentatively remove the base service.
    949    */
    950   bus_connection_add_owned_service_link (d->owner->conn, d->service_link);
    951 
    952   d->hash_entry = NULL;
    953   d->service_link = NULL;
    954   d->owner_link = NULL;
    955 }
    956 
    957 static void
    958 free_ownership_restore_data (void *data)
    959 {
    960   OwnershipRestoreData *d = data;
    961 
    962   if (d->service_link)
    963     _dbus_list_free_link (d->service_link);
    964   if (d->owner_link)
    965     _dbus_list_free_link (d->owner_link);
    966   if (d->hash_entry)
    967     _dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash,
    968                                               d->hash_entry);
    969 
    970   dbus_connection_unref (d->owner->conn);
    971   bus_owner_unref (d->owner);
    972   bus_service_unref (d->service);
    973 
    974   dbus_free (d);
    975 }
    976 
    977 static dbus_bool_t
    978 add_restore_ownership_to_transaction (BusTransaction *transaction,
    979                                       BusService     *service,
    980                                       BusOwner       *owner)
    981 {
    982   OwnershipRestoreData *d;
    983   DBusList *link;
    984 
    985   d = dbus_new (OwnershipRestoreData, 1);
    986   if (d == NULL)
    987     return FALSE;
    988 
    989   d->service = service;
    990   d->owner = owner;
    991   d->service_link = _dbus_list_alloc_link (service);
    992   d->owner_link = _dbus_list_alloc_link (owner);
    993   d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash);
    994 
    995   bus_service_ref (d->service);
    996   bus_owner_ref (d->owner);
    997   dbus_connection_ref (d->owner->conn);
    998 
    999   d->before_owner = NULL;
   1000   link = _dbus_list_get_first_link (&service->owners);
   1001   while (link != NULL)
   1002     {
   1003       if (link->data == owner)
   1004         {
   1005           link = _dbus_list_get_next_link (&service->owners, link);
   1006 
   1007           if (link)
   1008             d->before_owner = link->data;
   1009 
   1010           break;
   1011         }
   1012 
   1013       link = _dbus_list_get_next_link (&service->owners, link);
   1014     }
   1015 
   1016   if (d->service_link == NULL ||
   1017       d->owner_link == NULL ||
   1018       d->hash_entry == NULL ||
   1019       !bus_transaction_add_cancel_hook (transaction, restore_ownership, d,
   1020                                         free_ownership_restore_data))
   1021     {
   1022       free_ownership_restore_data (d);
   1023       return FALSE;
   1024     }
   1025 
   1026   return TRUE;
   1027 }
   1028 
   1029 dbus_bool_t
   1030 bus_service_swap_owner (BusService     *service,
   1031                         DBusConnection *connection,
   1032                         BusTransaction *transaction,
   1033                         DBusError      *error)
   1034 {
   1035   DBusList *swap_link;
   1036   BusOwner *primary_owner;
   1037 
   1038   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   1039 
   1040   /* We send out notifications before we do any work we
   1041    * might have to undo if the notification-sending failed
   1042    */
   1043 
   1044   /* Send service lost message */
   1045   primary_owner = bus_service_get_primary_owner (service);
   1046   if (primary_owner == NULL || primary_owner->conn != connection)
   1047     _dbus_assert_not_reached ("Tried to swap a non primary owner");
   1048 
   1049 
   1050   if (!bus_driver_send_service_lost (connection, service->name,
   1051                                      transaction, error))
   1052     return FALSE;
   1053 
   1054   if (service->owners == NULL)
   1055     {
   1056       _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners");
   1057     }
   1058   else if (_dbus_list_length_is_one (&service->owners))
   1059     {
   1060       _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue");
   1061     }
   1062   else
   1063     {
   1064       DBusList *link;
   1065       BusOwner *new_owner;
   1066       DBusConnection *new_owner_conn;
   1067       link = _dbus_list_get_first_link (&service->owners);
   1068       _dbus_assert (link != NULL);
   1069       link = _dbus_list_get_next_link (&service->owners, link);
   1070       _dbus_assert (link != NULL);
   1071 
   1072       new_owner = (BusOwner *)link->data;
   1073       new_owner_conn = new_owner->conn;
   1074 
   1075       if (!bus_driver_send_service_owner_changed (service->name,
   1076  						  bus_connection_get_name (connection),
   1077  						  bus_connection_get_name (new_owner_conn),
   1078  						  transaction, error))
   1079         return FALSE;
   1080 
   1081       /* This will be our new owner */
   1082       if (!bus_driver_send_service_acquired (new_owner_conn,
   1083                                              service->name,
   1084                                              transaction,
   1085                                              error))
   1086         return FALSE;
   1087     }
   1088 
   1089   if (!add_restore_ownership_to_transaction (transaction, service, primary_owner))
   1090     {
   1091       BUS_SET_OOM (error);
   1092       return FALSE;
   1093     }
   1094 
   1095   /* unlink the primary and make it the second link */
   1096   swap_link = _dbus_list_get_first_link (&service->owners);
   1097   _dbus_list_unlink (&service->owners, swap_link);
   1098 
   1099   _dbus_list_insert_after_link (&service->owners,
   1100                                 _dbus_list_get_first_link (&service->owners),
   1101 				swap_link);
   1102 
   1103   return TRUE;
   1104 }
   1105 
   1106 /* this function is self-cancelling if you cancel the transaction */
   1107 dbus_bool_t
   1108 bus_service_remove_owner (BusService     *service,
   1109                           DBusConnection *connection,
   1110                           BusTransaction *transaction,
   1111                           DBusError      *error)
   1112 {
   1113   BusOwner *primary_owner;
   1114 
   1115   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   1116 
   1117   /* We send out notifications before we do any work we
   1118    * might have to undo if the notification-sending failed
   1119    */
   1120 
   1121   /* Send service lost message */
   1122   primary_owner = bus_service_get_primary_owner (service);
   1123   if (primary_owner != NULL && primary_owner->conn == connection)
   1124     {
   1125       if (!bus_driver_send_service_lost (connection, service->name,
   1126                                          transaction, error))
   1127         return FALSE;
   1128     }
   1129   else
   1130     {
   1131       /* if we are not the primary owner then just remove us from the queue */
   1132       DBusList *link;
   1133       BusOwner *temp_owner;
   1134 
   1135       link = _bus_service_find_owner_link (service, connection);
   1136       _dbus_list_unlink (&service->owners, link);
   1137       temp_owner = (BusOwner *)link->data;
   1138       bus_owner_unref (temp_owner);
   1139       _dbus_list_free_link (link);
   1140 
   1141       return TRUE;
   1142     }
   1143 
   1144   if (service->owners == NULL)
   1145     {
   1146       _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners");
   1147     }
   1148   else if (_dbus_list_length_is_one (&service->owners))
   1149     {
   1150       if (!bus_driver_send_service_owner_changed (service->name,
   1151  						  bus_connection_get_name (connection),
   1152  						  NULL,
   1153  						  transaction, error))
   1154         return FALSE;
   1155     }
   1156   else
   1157     {
   1158       DBusList *link;
   1159       BusOwner *new_owner;
   1160       DBusConnection *new_owner_conn;
   1161       link = _dbus_list_get_first_link (&service->owners);
   1162       _dbus_assert (link != NULL);
   1163       link = _dbus_list_get_next_link (&service->owners, link);
   1164       _dbus_assert (link != NULL);
   1165 
   1166       new_owner = (BusOwner *)link->data;
   1167       new_owner_conn = new_owner->conn;
   1168 
   1169       if (!bus_driver_send_service_owner_changed (service->name,
   1170  						  bus_connection_get_name (connection),
   1171  						  bus_connection_get_name (new_owner_conn),
   1172  						  transaction, error))
   1173         return FALSE;
   1174 
   1175       /* This will be our new owner */
   1176       if (!bus_driver_send_service_acquired (new_owner_conn,
   1177                                              service->name,
   1178                                              transaction,
   1179                                              error))
   1180         return FALSE;
   1181     }
   1182 
   1183   if (!add_restore_ownership_to_transaction (transaction, service, primary_owner))
   1184     {
   1185       BUS_SET_OOM (error);
   1186       return FALSE;
   1187     }
   1188 
   1189   bus_service_unlink_owner (service, primary_owner);
   1190 
   1191   if (service->owners == NULL)
   1192     bus_service_unlink (service);
   1193 
   1194   return TRUE;
   1195 }
   1196 
   1197 BusService *
   1198 bus_service_ref (BusService *service)
   1199 {
   1200   _dbus_assert (service->refcount > 0);
   1201 
   1202   service->refcount += 1;
   1203 
   1204   return service;
   1205 }
   1206 
   1207 void
   1208 bus_service_unref (BusService *service)
   1209 {
   1210   _dbus_assert (service->refcount > 0);
   1211 
   1212   service->refcount -= 1;
   1213 
   1214   if (service->refcount == 0)
   1215     {
   1216       _dbus_assert (service->owners == NULL);
   1217 
   1218       dbus_free (service->name);
   1219       _dbus_mem_pool_dealloc (service->registry->service_pool, service);
   1220     }
   1221 }
   1222 
   1223 DBusConnection *
   1224 bus_service_get_primary_owners_connection (BusService *service)
   1225 {
   1226   BusOwner *owner;
   1227 
   1228   owner = bus_service_get_primary_owner (service);
   1229 
   1230   if (owner != NULL)
   1231     return owner->conn;
   1232   else
   1233     return NULL;
   1234 }
   1235 
   1236 BusOwner*
   1237 bus_service_get_primary_owner (BusService *service)
   1238 {
   1239   return _dbus_list_get_first (&service->owners);
   1240 }
   1241 
   1242 const char*
   1243 bus_service_get_name (BusService *service)
   1244 {
   1245   return service->name;
   1246 }
   1247 
   1248 dbus_bool_t
   1249 bus_service_get_allow_replacement (BusService *service)
   1250 {
   1251   BusOwner *owner;
   1252   DBusList *link;
   1253 
   1254   _dbus_assert (service->owners != NULL);
   1255 
   1256   link = _dbus_list_get_first_link (&service->owners);
   1257   owner = (BusOwner *) link->data;
   1258 
   1259   return owner->allow_replacement;
   1260 }
   1261 
   1262 dbus_bool_t
   1263 bus_service_has_owner (BusService     *service,
   1264 		       DBusConnection *connection)
   1265 {
   1266   DBusList *link;
   1267 
   1268   link = _bus_service_find_owner_link (service, connection);
   1269 
   1270   if (link == NULL)
   1271     return FALSE;
   1272   else
   1273     return TRUE;
   1274 }
   1275 
   1276 dbus_bool_t
   1277 bus_service_list_queued_owners (BusService *service,
   1278                                 DBusList  **return_list,
   1279                                 DBusError  *error)
   1280 {
   1281   DBusList *link;
   1282 
   1283   _dbus_assert (*return_list == NULL);
   1284 
   1285   link = _dbus_list_get_first_link (&service->owners);
   1286   _dbus_assert (link != NULL);
   1287 
   1288   while (link != NULL)
   1289     {
   1290       BusOwner *owner;
   1291       const char *uname;
   1292 
   1293       owner = (BusOwner *) link->data;
   1294       uname = bus_connection_get_name (owner->conn);
   1295 
   1296       if (!_dbus_list_append (return_list, (char *)uname))
   1297         goto oom;
   1298 
   1299       link = _dbus_list_get_next_link (&service->owners, link);
   1300     }
   1301 
   1302   return TRUE;
   1303 
   1304  oom:
   1305   _dbus_list_clear (return_list);
   1306   BUS_SET_OOM (error);
   1307   return FALSE;
   1308 }
   1309