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