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