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