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