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   BusClientPolicy *policy;
389   BusService *service;
390   BusActivation  *activation;
391   BusSELinuxID *sid;
392   BusOwner *primary_owner;
393 
394   retval = FALSE;
395 
396   if (!_dbus_validate_bus_name (service_name, 0,
397                                 _dbus_string_get_length (service_name)))
398     {
399       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
400                       "Requested bus name \"%s\" is not valid",
401                       _dbus_string_get_const_data (service_name));
402 
403       _dbus_verbose ("Attempt to acquire invalid service name\n");
404 
405       goto out;
406     }
407 
408   if (_dbus_string_get_byte (service_name, 0) == ':')
409     {
410       /* Not allowed; only base services can start with ':' */
411       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
412                       "Cannot acquire a service starting with ':' such as \"%s\"",
413                       _dbus_string_get_const_data (service_name));
414 
415       _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"",
416                      _dbus_string_get_const_data (service_name));
417 
418       goto out;
419     }
420 
421   if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS))
422     {
423       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
424                       "Connection \"%s\" is not allowed to own the service \"%s\"because "
425                       "it is reserved for D-Bus' use only",
426                       bus_connection_is_active (connection) ?
427                       bus_connection_get_name (connection) :
428                       "(inactive)",
429                       DBUS_SERVICE_DBUS);
430       goto out;
431     }
432 
433   policy = bus_connection_get_policy (connection);
434   _dbus_assert (policy != NULL);
435 
436   /* Note that if sid is #NULL then the bus's own context gets used
437    * in bus_connection_selinux_allows_acquire_service()
438    */
439   sid = bus_selinux_id_table_lookup (registry->service_sid_table,
440                                      service_name);
441 
442   if (!bus_selinux_allows_acquire_service (connection, sid,
443 					   _dbus_string_get_const_data (service_name), error))
444     {
445 
446       if (dbus_error_is_set (error) &&
447 	  dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY))
448 	{
449 	  goto out;
450 	}
451 
452       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
453                       "Connection \"%s\" is not allowed to own the service \"%s\" due "
454                       "to SELinux policy",
455                       bus_connection_is_active (connection) ?
456                       bus_connection_get_name (connection) :
457                       "(inactive)",
458                       _dbus_string_get_const_data (service_name));
459       goto out;
460     }
461 
462   if (!bus_client_policy_check_can_own (policy, service_name))
463     {
464       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
465                       "Connection \"%s\" is not allowed to own the service \"%s\" due "
466                       "to security policies in the configuration file",
467                       bus_connection_is_active (connection) ?
468                       bus_connection_get_name (connection) :
469                       "(inactive)",
470                       _dbus_string_get_const_data (service_name));
471       goto out;
472     }
473 
474   if (bus_connection_get_n_services_owned (connection) >=
475       bus_context_get_max_services_per_connection (registry->context))
476     {
477       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
478                       "Connection \"%s\" is not allowed to own more services "
479                       "(increase limits in configuration file if required)",
480                       bus_connection_is_active (connection) ?
481                       bus_connection_get_name (connection) :
482                       "(inactive)");
483       goto out;
484     }
485 
486   service = bus_registry_lookup (registry, service_name);
487 
488   if (service != NULL)
489     {
490       primary_owner = bus_service_get_primary_owner (service);
491       if (primary_owner != NULL)
492         old_owner_conn = primary_owner->conn;
493       else
494         old_owner_conn = NULL;
495     }
496   else
497     old_owner_conn = NULL;
498 
499   if (service == NULL)
500     {
501       service = bus_registry_ensure (registry,
502                                      service_name, connection, flags,
503                                      transaction, error);
504       if (service == NULL)
505         goto out;
506     }
507 
508   primary_owner = bus_service_get_primary_owner (service);
509   if (primary_owner == NULL)
510     goto out;
511 
512   if (old_owner_conn == NULL)
513     {
514       _dbus_assert (primary_owner->conn == connection);
515 
516       *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
517     }
518   else if (old_owner_conn == connection)
519     {
520       bus_owner_set_flags (primary_owner, flags);
521       *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
522     }
523   else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
524            !(bus_service_get_allow_replacement (service))) ||
525 	   ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
526            !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING)))
527     {
528       DBusList *link;
529       BusOwner *temp_owner;
530     /* Since we can't be queued if we are already in the queue
531        remove us */
532 
533       link = _bus_service_find_owner_link (service, connection);
534       if (link != NULL)
535         {
536           _dbus_list_unlink (&service->owners, link);
537           temp_owner = (BusOwner *)link->data;
538           bus_owner_unref (temp_owner);
539           _dbus_list_free_link (link);
540         }
541 
542       *result = DBUS_REQUEST_NAME_REPLY_EXISTS;
543     }
544   else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
545            (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) ||
546 	    !(bus_service_get_allow_replacement (service))))
547     {
548       /* Queue the connection */
549       if (!bus_service_add_owner (service, connection,
550                                   flags,
551                                   transaction, error))
552         goto out;
553 
554       *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE;
555     }
556   else
557     {
558       /* Replace the current owner */
559 
560       /* We enqueue the new owner and remove the first one because
561        * that will cause NameAcquired and NameLost messages to
562        * be sent.
563        */
564 
565       if (!bus_service_add_owner (service, connection,
566                                   flags,
567                                   transaction, error))
568         goto out;
569 
570       if (primary_owner->do_not_queue)
571         {
572           if (!bus_service_remove_owner (service, old_owner_conn,
573                                          transaction, error))
574             goto out;
575         }
576       else
577         {
578           if (!bus_service_swap_owner (service, old_owner_conn,
579                                        transaction, error))
580             goto out;
581         }
582 
583 
584       _dbus_assert (connection == bus_service_get_primary_owner (service)->conn);
585       *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
586     }
587 
588   activation = bus_context_get_activation (registry->context);
589   retval = bus_activation_send_pending_auto_activation_messages (activation,
590 								 service,
591 								 transaction,
592 								 error);
593 
594  out:
595   return retval;
596 }
597 
598 dbus_bool_t
bus_registry_release_service(BusRegistry * registry,DBusConnection * connection,const DBusString * service_name,dbus_uint32_t * result,BusTransaction * transaction,DBusError * error)599 bus_registry_release_service (BusRegistry      *registry,
600                               DBusConnection   *connection,
601                               const DBusString *service_name,
602                               dbus_uint32_t    *result,
603                               BusTransaction   *transaction,
604                               DBusError        *error)
605 {
606   dbus_bool_t retval;
607   BusService *service;
608 
609   retval = FALSE;
610 
611   if (!_dbus_validate_bus_name (service_name, 0,
612                                 _dbus_string_get_length (service_name)))
613     {
614       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
615                       "Given bus name \"%s\" is not valid",
616                       _dbus_string_get_const_data (service_name));
617 
618       _dbus_verbose ("Attempt to release invalid service name\n");
619 
620       goto out;
621     }
622 
623   if (_dbus_string_get_byte (service_name, 0) == ':')
624     {
625       /* Not allowed; the base service name cannot be created or released */
626       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
627                       "Cannot release a service starting with ':' such as \"%s\"",
628                       _dbus_string_get_const_data (service_name));
629 
630       _dbus_verbose ("Attempt to release invalid base service name \"%s\"",
631                      _dbus_string_get_const_data (service_name));
632 
633       goto out;
634     }
635 
636    if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS))
637     {
638       /* Not allowed; the base service name cannot be created or released */
639       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
640                       "Cannot release the %s service because it is owned by the bus",
641                      DBUS_SERVICE_DBUS);
642 
643       _dbus_verbose ("Attempt to release service name \"%s\"",
644                      DBUS_SERVICE_DBUS);
645 
646       goto out;
647     }
648 
649   service = bus_registry_lookup (registry, service_name);
650 
651   if (service == NULL)
652     {
653       *result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT;
654     }
655   else if (!bus_service_has_owner (service, connection))
656     {
657       *result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER;
658     }
659   else
660     {
661       if (!bus_service_remove_owner (service, connection,
662                                      transaction, error))
663         goto out;
664 
665       _dbus_assert (!bus_service_has_owner (service, connection));
666       *result = DBUS_RELEASE_NAME_REPLY_RELEASED;
667     }
668 
669   retval = TRUE;
670 
671  out:
672   return retval;
673 }
674 
675 dbus_bool_t
bus_registry_set_service_context_table(BusRegistry * registry,DBusHashTable * table)676 bus_registry_set_service_context_table (BusRegistry   *registry,
677 					DBusHashTable *table)
678 {
679   DBusHashTable *new_table;
680   DBusHashIter iter;
681 
682   new_table = bus_selinux_id_table_new ();
683   if (!new_table)
684     return FALSE;
685 
686   _dbus_hash_iter_init (table, &iter);
687   while (_dbus_hash_iter_next (&iter))
688     {
689       const char *service = _dbus_hash_iter_get_string_key (&iter);
690       const char *context = _dbus_hash_iter_get_value (&iter);
691 
692       if (!bus_selinux_id_table_insert (new_table,
693 					service,
694 					context))
695 	return FALSE;
696     }
697 
698   if (registry->service_sid_table)
699     _dbus_hash_table_unref (registry->service_sid_table);
700   registry->service_sid_table = new_table;
701   return TRUE;
702 }
703 
704 static void
bus_service_unlink_owner(BusService * service,BusOwner * owner)705 bus_service_unlink_owner (BusService      *service,
706                           BusOwner        *owner)
707 {
708   _dbus_list_remove_last (&service->owners, owner);
709   bus_owner_unref (owner);
710 }
711 
712 static void
bus_service_unlink(BusService * service)713 bus_service_unlink (BusService *service)
714 {
715   _dbus_assert (service->owners == NULL);
716 
717   /* the service may not be in the hash, if
718    * the failure causing transaction cancel
719    * was in the right place, but that's OK
720    */
721   _dbus_hash_table_remove_string (service->registry->service_hash,
722                                   service->name);
723 
724   bus_service_unref (service);
725 }
726 
727 static void
bus_service_relink(BusService * service,DBusPreallocatedHash * preallocated)728 bus_service_relink (BusService           *service,
729                     DBusPreallocatedHash *preallocated)
730 {
731   _dbus_assert (service->owners == NULL);
732   _dbus_assert (preallocated != NULL);
733 
734   _dbus_hash_table_insert_string_preallocated (service->registry->service_hash,
735                                                preallocated,
736                                                service->name,
737                                                service);
738 
739   bus_service_ref (service);
740 }
741 
742 /**
743  * Data used to represent an ownership cancellation in
744  * a bus transaction.
745  */
746 typedef struct
747 {
748   BusOwner *owner;            /**< the owner */
749   BusService *service;        /**< service to cancel ownership of */
750 } OwnershipCancelData;
751 
752 static void
cancel_ownership(void * data)753 cancel_ownership (void *data)
754 {
755   OwnershipCancelData *d = data;
756 
757   /* We don't need to send messages notifying of these
758    * changes, since we're reverting something that was
759    * cancelled (effectively never really happened)
760    */
761   bus_service_unlink_owner (d->service, d->owner);
762 
763   if (d->service->owners == NULL)
764     bus_service_unlink (d->service);
765 }
766 
767 static void
free_ownership_cancel_data(void * data)768 free_ownership_cancel_data (void *data)
769 {
770   OwnershipCancelData *d = data;
771 
772   dbus_connection_unref (d->owner->conn);
773   bus_owner_unref (d->owner);
774   bus_service_unref (d->service);
775 
776   dbus_free (d);
777 }
778 
779 static dbus_bool_t
add_cancel_ownership_to_transaction(BusTransaction * transaction,BusService * service,BusOwner * owner)780 add_cancel_ownership_to_transaction (BusTransaction *transaction,
781                                      BusService     *service,
782                                      BusOwner       *owner)
783 {
784   OwnershipCancelData *d;
785 
786   d = dbus_new (OwnershipCancelData, 1);
787   if (d == NULL)
788     return FALSE;
789 
790   d->service = service;
791   d->owner = owner;
792 
793   if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d,
794                                         free_ownership_cancel_data))
795     {
796       dbus_free (d);
797       return FALSE;
798     }
799 
800   bus_service_ref (d->service);
801   bus_owner_ref (owner);
802   dbus_connection_ref (d->owner->conn);
803 
804   return TRUE;
805 }
806 
807 /* this function is self-cancelling if you cancel the transaction */
808 dbus_bool_t
bus_service_add_owner(BusService * service,DBusConnection * connection,dbus_uint32_t flags,BusTransaction * transaction,DBusError * error)809 bus_service_add_owner (BusService     *service,
810                        DBusConnection *connection,
811                        dbus_uint32_t  flags,
812                        BusTransaction *transaction,
813                        DBusError      *error)
814 {
815   BusOwner *bus_owner;
816   DBusList *bus_owner_link;
817 
818   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
819 
820  /* Send service acquired message first, OOM will result
821   * in cancelling the transaction
822   */
823   if (service->owners == NULL)
824     {
825       if (!bus_driver_send_service_acquired (connection, service->name, transaction, error))
826         return FALSE;
827     }
828 
829   bus_owner_link = _bus_service_find_owner_link (service, connection);
830 
831   if (bus_owner_link == NULL)
832     {
833       bus_owner = bus_owner_new (service, connection, flags);
834       if (bus_owner == NULL)
835         {
836           BUS_SET_OOM (error);
837           return FALSE;
838         }
839 
840       bus_owner_set_flags (bus_owner, flags);
841       if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL)
842         {
843           if (!_dbus_list_append (&service->owners,
844                                   bus_owner))
845             {
846               bus_owner_unref (bus_owner);
847               BUS_SET_OOM (error);
848               return FALSE;
849             }
850         }
851       else
852         {
853           if (!_dbus_list_insert_after (&service->owners,
854                                          _dbus_list_get_first_link (&service->owners),
855                                          bus_owner))
856             {
857               bus_owner_unref (bus_owner);
858               BUS_SET_OOM (error);
859               return FALSE;
860             }
861         }
862     }
863   else
864     {
865       /* Update the link since we are already in the queue
866        * No need for operations that can produce OOM
867        */
868 
869       bus_owner = (BusOwner *) bus_owner_link->data;
870       if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING)
871         {
872 	  DBusList *link;
873           _dbus_list_unlink (&service->owners, bus_owner_link);
874 	  link = _dbus_list_get_first_link (&service->owners);
875 	  _dbus_assert (link != NULL);
876 
877           _dbus_list_insert_after_link (&service->owners, link, bus_owner_link);
878         }
879 
880       bus_owner_set_flags (bus_owner, flags);
881       return TRUE;
882     }
883 
884   if (!add_cancel_ownership_to_transaction (transaction,
885                                             service,
886                                             bus_owner))
887     {
888       bus_service_unlink_owner (service, bus_owner);
889       BUS_SET_OOM (error);
890       return FALSE;
891     }
892 
893   return TRUE;
894 }
895 
896 typedef struct
897 {
898   BusOwner       *owner;
899   BusService     *service;
900   BusOwner       *before_owner; /* restore to position before this connection in owners list */
901   DBusList       *owner_link;
902   DBusList       *service_link;
903   DBusPreallocatedHash *hash_entry;
904 } OwnershipRestoreData;
905 
906 static void
restore_ownership(void * data)907 restore_ownership (void *data)
908 {
909   OwnershipRestoreData *d = data;
910   DBusList *link;
911 
912   _dbus_assert (d->service_link != NULL);
913   _dbus_assert (d->owner_link != NULL);
914 
915   if (d->service->owners == NULL)
916     {
917       _dbus_assert (d->hash_entry != NULL);
918       bus_service_relink (d->service, d->hash_entry);
919     }
920   else
921     {
922       _dbus_assert (d->hash_entry == NULL);
923     }
924 
925   /* We don't need to send messages notifying of these
926    * changes, since we're reverting something that was
927    * cancelled (effectively never really happened)
928    */
929   link = _dbus_list_get_first_link (&d->service->owners);
930   while (link != NULL)
931     {
932       if (link->data == d->before_owner)
933         break;
934 
935       link = _dbus_list_get_next_link (&d->service->owners, link);
936     }
937 
938   _dbus_list_insert_before_link (&d->service->owners, link, d->owner_link);
939 
940   /* Note that removing then restoring this changes the order in which
941    * ServiceDeleted messages are sent on destruction of the
942    * connection.  This should be OK as the only guarantee there is
943    * that the base service is destroyed last, and we never even
944    * tentatively remove the base service.
945    */
946   bus_connection_add_owned_service_link (d->owner->conn, d->service_link);
947 
948   d->hash_entry = NULL;
949   d->service_link = NULL;
950   d->owner_link = NULL;
951 }
952 
953 static void
free_ownership_restore_data(void * data)954 free_ownership_restore_data (void *data)
955 {
956   OwnershipRestoreData *d = data;
957 
958   if (d->service_link)
959     _dbus_list_free_link (d->service_link);
960   if (d->owner_link)
961     _dbus_list_free_link (d->owner_link);
962   if (d->hash_entry)
963     _dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash,
964                                               d->hash_entry);
965 
966   dbus_connection_unref (d->owner->conn);
967   bus_owner_unref (d->owner);
968   bus_service_unref (d->service);
969 
970   dbus_free (d);
971 }
972 
973 static dbus_bool_t
add_restore_ownership_to_transaction(BusTransaction * transaction,BusService * service,BusOwner * owner)974 add_restore_ownership_to_transaction (BusTransaction *transaction,
975                                       BusService     *service,
976                                       BusOwner       *owner)
977 {
978   OwnershipRestoreData *d;
979   DBusList *link;
980 
981   d = dbus_new (OwnershipRestoreData, 1);
982   if (d == NULL)
983     return FALSE;
984 
985   d->service = service;
986   d->owner = owner;
987   d->service_link = _dbus_list_alloc_link (service);
988   d->owner_link = _dbus_list_alloc_link (owner);
989   d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash);
990 
991   bus_service_ref (d->service);
992   bus_owner_ref (d->owner);
993   dbus_connection_ref (d->owner->conn);
994 
995   d->before_owner = NULL;
996   link = _dbus_list_get_first_link (&service->owners);
997   while (link != NULL)
998     {
999       if (link->data == owner)
1000         {
1001           link = _dbus_list_get_next_link (&service->owners, link);
1002 
1003           if (link)
1004             d->before_owner = link->data;
1005 
1006           break;
1007         }
1008 
1009       link = _dbus_list_get_next_link (&service->owners, link);
1010     }
1011 
1012   if (d->service_link == NULL ||
1013       d->owner_link == NULL ||
1014       d->hash_entry == NULL ||
1015       !bus_transaction_add_cancel_hook (transaction, restore_ownership, d,
1016                                         free_ownership_restore_data))
1017     {
1018       free_ownership_restore_data (d);
1019       return FALSE;
1020     }
1021 
1022   return TRUE;
1023 }
1024 
1025 dbus_bool_t
bus_service_swap_owner(BusService * service,DBusConnection * connection,BusTransaction * transaction,DBusError * error)1026 bus_service_swap_owner (BusService     *service,
1027                         DBusConnection *connection,
1028                         BusTransaction *transaction,
1029                         DBusError      *error)
1030 {
1031   DBusList *swap_link;
1032   BusOwner *primary_owner;
1033 
1034   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1035 
1036   /* We send out notifications before we do any work we
1037    * might have to undo if the notification-sending failed
1038    */
1039 
1040   /* Send service lost message */
1041   primary_owner = bus_service_get_primary_owner (service);
1042   if (primary_owner == NULL || primary_owner->conn != connection)
1043     _dbus_assert_not_reached ("Tried to swap a non primary owner");
1044 
1045 
1046   if (!bus_driver_send_service_lost (connection, service->name,
1047                                      transaction, error))
1048     return FALSE;
1049 
1050   if (service->owners == NULL)
1051     {
1052       _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners");
1053     }
1054   else if (_dbus_list_length_is_one (&service->owners))
1055     {
1056       _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue");
1057     }
1058   else
1059     {
1060       DBusList *link;
1061       BusOwner *new_owner;
1062       DBusConnection *new_owner_conn;
1063       link = _dbus_list_get_first_link (&service->owners);
1064       _dbus_assert (link != NULL);
1065       link = _dbus_list_get_next_link (&service->owners, link);
1066       _dbus_assert (link != NULL);
1067 
1068       new_owner = (BusOwner *)link->data;
1069       new_owner_conn = new_owner->conn;
1070 
1071       if (!bus_driver_send_service_owner_changed (service->name,
1072  						  bus_connection_get_name (connection),
1073  						  bus_connection_get_name (new_owner_conn),
1074  						  transaction, error))
1075         return FALSE;
1076 
1077       /* This will be our new owner */
1078       if (!bus_driver_send_service_acquired (new_owner_conn,
1079                                              service->name,
1080                                              transaction,
1081                                              error))
1082         return FALSE;
1083     }
1084 
1085   if (!add_restore_ownership_to_transaction (transaction, service, primary_owner))
1086     {
1087       BUS_SET_OOM (error);
1088       return FALSE;
1089     }
1090 
1091   /* unlink the primary and make it the second link */
1092   swap_link = _dbus_list_get_first_link (&service->owners);
1093   _dbus_list_unlink (&service->owners, swap_link);
1094 
1095   _dbus_list_insert_after_link (&service->owners,
1096                                 _dbus_list_get_first_link (&service->owners),
1097 				swap_link);
1098 
1099   return TRUE;
1100 }
1101 
1102 /* this function is self-cancelling if you cancel the transaction */
1103 dbus_bool_t
bus_service_remove_owner(BusService * service,DBusConnection * connection,BusTransaction * transaction,DBusError * error)1104 bus_service_remove_owner (BusService     *service,
1105                           DBusConnection *connection,
1106                           BusTransaction *transaction,
1107                           DBusError      *error)
1108 {
1109   BusOwner *primary_owner;
1110 
1111   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1112 
1113   /* We send out notifications before we do any work we
1114    * might have to undo if the notification-sending failed
1115    */
1116 
1117   /* Send service lost message */
1118   primary_owner = bus_service_get_primary_owner (service);
1119   if (primary_owner != NULL && primary_owner->conn == connection)
1120     {
1121       if (!bus_driver_send_service_lost (connection, service->name,
1122                                          transaction, error))
1123         return FALSE;
1124     }
1125   else
1126     {
1127       /* if we are not the primary owner then just remove us from the queue */
1128       DBusList *link;
1129       BusOwner *temp_owner;
1130 
1131       link = _bus_service_find_owner_link (service, connection);
1132       _dbus_list_unlink (&service->owners, link);
1133       temp_owner = (BusOwner *)link->data;
1134       bus_owner_unref (temp_owner);
1135       _dbus_list_free_link (link);
1136 
1137       return TRUE;
1138     }
1139 
1140   if (service->owners == NULL)
1141     {
1142       _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners");
1143     }
1144   else if (_dbus_list_length_is_one (&service->owners))
1145     {
1146       if (!bus_driver_send_service_owner_changed (service->name,
1147  						  bus_connection_get_name (connection),
1148  						  NULL,
1149  						  transaction, error))
1150         return FALSE;
1151     }
1152   else
1153     {
1154       DBusList *link;
1155       BusOwner *new_owner;
1156       DBusConnection *new_owner_conn;
1157       link = _dbus_list_get_first_link (&service->owners);
1158       _dbus_assert (link != NULL);
1159       link = _dbus_list_get_next_link (&service->owners, link);
1160       _dbus_assert (link != NULL);
1161 
1162       new_owner = (BusOwner *)link->data;
1163       new_owner_conn = new_owner->conn;
1164 
1165       if (!bus_driver_send_service_owner_changed (service->name,
1166  						  bus_connection_get_name (connection),
1167  						  bus_connection_get_name (new_owner_conn),
1168  						  transaction, error))
1169         return FALSE;
1170 
1171       /* This will be our new owner */
1172       if (!bus_driver_send_service_acquired (new_owner_conn,
1173                                              service->name,
1174                                              transaction,
1175                                              error))
1176         return FALSE;
1177     }
1178 
1179   if (!add_restore_ownership_to_transaction (transaction, service, primary_owner))
1180     {
1181       BUS_SET_OOM (error);
1182       return FALSE;
1183     }
1184 
1185   bus_service_unlink_owner (service, primary_owner);
1186 
1187   if (service->owners == NULL)
1188     bus_service_unlink (service);
1189 
1190   return TRUE;
1191 }
1192 
1193 BusService *
bus_service_ref(BusService * service)1194 bus_service_ref (BusService *service)
1195 {
1196   _dbus_assert (service->refcount > 0);
1197 
1198   service->refcount += 1;
1199 
1200   return service;
1201 }
1202 
1203 void
bus_service_unref(BusService * service)1204 bus_service_unref (BusService *service)
1205 {
1206   _dbus_assert (service->refcount > 0);
1207 
1208   service->refcount -= 1;
1209 
1210   if (service->refcount == 0)
1211     {
1212       _dbus_assert (service->owners == NULL);
1213 
1214       dbus_free (service->name);
1215       _dbus_mem_pool_dealloc (service->registry->service_pool, service);
1216     }
1217 }
1218 
1219 DBusConnection *
bus_service_get_primary_owners_connection(BusService * service)1220 bus_service_get_primary_owners_connection (BusService *service)
1221 {
1222   BusOwner *owner;
1223 
1224   owner = bus_service_get_primary_owner (service);
1225 
1226   if (owner != NULL)
1227     return owner->conn;
1228   else
1229     return NULL;
1230 }
1231 
1232 BusOwner*
bus_service_get_primary_owner(BusService * service)1233 bus_service_get_primary_owner (BusService *service)
1234 {
1235   return _dbus_list_get_first (&service->owners);
1236 }
1237 
1238 const char*
bus_service_get_name(BusService * service)1239 bus_service_get_name (BusService *service)
1240 {
1241   return service->name;
1242 }
1243 
1244 dbus_bool_t
bus_service_get_allow_replacement(BusService * service)1245 bus_service_get_allow_replacement (BusService *service)
1246 {
1247   BusOwner *owner;
1248   DBusList *link;
1249 
1250   _dbus_assert (service->owners != NULL);
1251 
1252   link = _dbus_list_get_first_link (&service->owners);
1253   owner = (BusOwner *) link->data;
1254 
1255   return owner->allow_replacement;
1256 }
1257 
1258 dbus_bool_t
bus_service_has_owner(BusService * service,DBusConnection * connection)1259 bus_service_has_owner (BusService     *service,
1260 		       DBusConnection *connection)
1261 {
1262   DBusList *link;
1263 
1264   link = _bus_service_find_owner_link (service, connection);
1265 
1266   if (link == NULL)
1267     return FALSE;
1268   else
1269     return TRUE;
1270 }
1271 
1272 dbus_bool_t
bus_service_list_queued_owners(BusService * service,DBusList ** return_list,DBusError * error)1273 bus_service_list_queued_owners (BusService *service,
1274                                 DBusList  **return_list,
1275                                 DBusError  *error)
1276 {
1277   DBusList *link;
1278 
1279   _dbus_assert (*return_list == NULL);
1280 
1281   link = _dbus_list_get_first_link (&service->owners);
1282   _dbus_assert (link != NULL);
1283 
1284   while (link != NULL)
1285     {
1286       BusOwner *owner;
1287       const char *uname;
1288 
1289       owner = (BusOwner *) link->data;
1290       uname = bus_connection_get_name (owner->conn);
1291 
1292       if (!_dbus_list_append (return_list, (char *)uname))
1293         goto oom;
1294 
1295       link = _dbus_list_get_next_link (&service->owners, link);
1296     }
1297 
1298   return TRUE;
1299 
1300  oom:
1301   _dbus_list_clear (return_list);
1302   BUS_SET_OOM (error);
1303   return FALSE;
1304 }
1305