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