2005-01-20 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / bus / services.c
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   unsigned int prohibit_replacement : 1;
47 };
48
49 struct BusRegistry
50 {
51   int refcount;
52
53   BusContext *context;
54   
55   DBusHashTable *service_hash;
56   DBusMemPool   *service_pool;
57
58   DBusHashTable *service_sid_table;
59 };
60
61 BusRegistry*
62 bus_registry_new (BusContext *context)
63 {
64   BusRegistry *registry;
65
66   registry = dbus_new0 (BusRegistry, 1);
67   if (registry == NULL)
68     return NULL;
69
70   registry->refcount = 1;
71   registry->context = context;
72   
73   registry->service_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
74                                                  NULL, NULL);
75   if (registry->service_hash == NULL)
76     goto failed;
77   
78   registry->service_pool = _dbus_mem_pool_new (sizeof (BusService),
79                                                TRUE);
80   if (registry->service_pool == NULL)
81     goto failed;
82
83   registry->service_sid_table = NULL;
84   
85   return registry;
86
87  failed:
88   bus_registry_unref (registry);
89   return NULL;
90 }
91
92 BusRegistry *
93 bus_registry_ref (BusRegistry *registry)
94 {
95   _dbus_assert (registry->refcount > 0);
96   registry->refcount += 1;
97
98   return registry;
99 }
100
101 void
102 bus_registry_unref  (BusRegistry *registry)
103 {
104   _dbus_assert (registry->refcount > 0);
105   registry->refcount -= 1;
106
107   if (registry->refcount == 0)
108     {
109       if (registry->service_hash)
110         _dbus_hash_table_unref (registry->service_hash);
111       if (registry->service_pool)
112         _dbus_mem_pool_free (registry->service_pool);
113       if (registry->service_sid_table)
114         _dbus_hash_table_unref (registry->service_sid_table);
115       
116       dbus_free (registry);
117     }
118 }
119
120 BusService*
121 bus_registry_lookup (BusRegistry      *registry,
122                      const DBusString *service_name)
123 {
124   BusService *service;
125
126   service = _dbus_hash_table_lookup_string (registry->service_hash,
127                                             _dbus_string_get_const_data (service_name));
128
129   return service;
130 }
131
132 BusService*
133 bus_registry_ensure (BusRegistry               *registry,
134                      const DBusString          *service_name,
135                      DBusConnection            *owner_if_created,
136                      BusTransaction            *transaction,
137                      DBusError                 *error)
138 {
139   BusService *service;
140
141   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
142   
143   _dbus_assert (owner_if_created != NULL);
144   _dbus_assert (transaction != NULL);
145
146   service = _dbus_hash_table_lookup_string (registry->service_hash,
147                                             _dbus_string_get_const_data (service_name));
148   if (service != NULL)
149     return service;
150   
151   service = _dbus_mem_pool_alloc (registry->service_pool);
152   if (service == NULL)
153     {
154       BUS_SET_OOM (error);
155       return NULL;
156     }
157
158   service->registry = registry;  
159   service->refcount = 1;
160
161   _dbus_verbose ("copying string %p '%s' to service->name\n",
162                  service_name, _dbus_string_get_const_data (service_name));
163   if (!_dbus_string_copy_data (service_name, &service->name))
164     {
165       _dbus_mem_pool_dealloc (registry->service_pool, service);
166       BUS_SET_OOM (error);
167       return NULL;
168     }
169   _dbus_verbose ("copied string %p '%s' to '%s'\n",
170                  service_name, _dbus_string_get_const_data (service_name),
171                  service->name);
172
173   if (!bus_driver_send_service_owner_changed (service->name, 
174                                               NULL,
175                                               bus_connection_get_name (owner_if_created),
176                                               transaction, error))
177     {
178       bus_service_unref (service);
179       return NULL;
180     }
181
182   if (!bus_activation_service_created (bus_context_get_activation (registry->context),
183                                        service->name, transaction, error))
184     {
185       bus_service_unref (service);
186       return NULL;
187     }
188   
189   if (!bus_service_add_owner (service, owner_if_created,
190                               transaction, error))
191     {
192       bus_service_unref (service);
193       return NULL;
194     }
195   
196   if (!_dbus_hash_table_insert_string (registry->service_hash,
197                                        service->name,
198                                        service))
199     {
200       /* The add_owner gets reverted on transaction cancel */
201       BUS_SET_OOM (error);
202       return NULL;
203     }
204   
205   return service;
206 }
207
208 void
209 bus_registry_foreach (BusRegistry               *registry,
210                       BusServiceForeachFunction  function,
211                       void                      *data)
212 {
213   DBusHashIter iter;
214   
215   _dbus_hash_iter_init (registry->service_hash, &iter);
216   while (_dbus_hash_iter_next (&iter))
217     {
218       BusService *service = _dbus_hash_iter_get_value (&iter);
219
220       (* function) (service, data);
221     }
222 }
223
224 dbus_bool_t
225 bus_registry_list_services (BusRegistry *registry,
226                             char      ***listp,
227                             int         *array_len)
228 {
229   int i, j, len;
230   char **retval;
231   DBusHashIter iter;
232    
233   len = _dbus_hash_table_get_n_entries (registry->service_hash);
234   retval = dbus_new (char *, len + 1);
235
236   if (retval == NULL)
237     return FALSE;
238
239   _dbus_hash_iter_init (registry->service_hash, &iter);
240   i = 0;
241   while (_dbus_hash_iter_next (&iter))
242     {
243       BusService *service = _dbus_hash_iter_get_value (&iter);
244
245       retval[i] = _dbus_strdup (service->name);
246       if (retval[i] == NULL)
247         goto error;
248
249       i++;
250     }
251
252   retval[i] = NULL;
253   
254   if (array_len)
255     *array_len = len;
256   
257   *listp = retval;
258   return TRUE;
259   
260  error:
261   for (j = 0; j < i; j++)
262     dbus_free (retval[i]);
263   dbus_free (retval);
264
265   return FALSE;
266 }
267
268 dbus_bool_t
269 bus_registry_acquire_service (BusRegistry      *registry,
270                               DBusConnection   *connection,
271                               const DBusString *service_name,
272                               dbus_uint32_t     flags,
273                               dbus_uint32_t    *result,
274                               BusTransaction   *transaction,
275                               DBusError        *error)
276 {
277   dbus_bool_t retval;
278   DBusConnection *old_owner;
279   DBusConnection *current_owner;
280   BusClientPolicy *policy;
281   BusService *service;
282   BusActivation  *activation;
283   BusSELinuxID *sid;
284   
285   retval = FALSE;
286
287   if (!_dbus_validate_bus_name (service_name, 0,
288                                 _dbus_string_get_length (service_name)))
289     {
290       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
291                       "Requested bus name \"%s\" is not valid",
292                       _dbus_string_get_const_data (service_name));
293       
294       _dbus_verbose ("Attempt to acquire invalid service name\n");
295       
296       goto out;
297     }
298   
299   if (_dbus_string_get_byte (service_name, 0) == ':')
300     {
301       /* Not allowed; only base services can start with ':' */
302       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
303                       "Cannot acquire a service starting with ':' such as \"%s\"",
304                       _dbus_string_get_const_data (service_name));
305       
306       _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"",
307                      _dbus_string_get_const_data (service_name));
308       
309       goto out;
310     }
311
312   policy = bus_connection_get_policy (connection);
313   _dbus_assert (policy != NULL);
314
315   /* Note that if sid is #NULL then the bus's own context gets used
316    * in bus_connection_selinux_allows_acquire_service()
317    */
318   sid = bus_selinux_id_table_lookup (registry->service_sid_table,
319                                      service_name);
320
321   if (!bus_selinux_allows_acquire_service (connection, sid,
322                                            _dbus_string_get_const_data (service_name)))
323     {
324       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
325                       "Connection \"%s\" is not allowed to own the service \"%s\" due "
326                       "to SELinux policy",
327                       bus_connection_is_active (connection) ?
328                       bus_connection_get_name (connection) :
329                       "(inactive)",
330                       _dbus_string_get_const_data (service_name));
331       goto out;
332     }
333       
334   if (!bus_client_policy_check_can_own (policy, connection,
335                                         service_name))
336     {
337       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
338                       "Connection \"%s\" is not allowed to own the service \"%s\" due "
339                       "to security policies in the configuration file",
340                       bus_connection_is_active (connection) ?
341                       bus_connection_get_name (connection) :
342                       "(inactive)",
343                       _dbus_string_get_const_data (service_name));
344       goto out;
345     }
346
347   if (bus_connection_get_n_services_owned (connection) >=
348       bus_context_get_max_services_per_connection (registry->context))
349     {
350       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
351                       "Connection \"%s\" is not allowed to own more services "
352                       "(increase limits in configuration file if required)",
353                       bus_connection_is_active (connection) ?
354                       bus_connection_get_name (connection) :
355                       "(inactive)");
356       goto out;
357     }
358   
359   service = bus_registry_lookup (registry, service_name);
360
361   if (service != NULL)
362     old_owner = bus_service_get_primary_owner (service);
363   else
364     old_owner = NULL;
365       
366   if (service == NULL)
367     {
368       service = bus_registry_ensure (registry,
369                                      service_name, connection, transaction, error);
370       if (service == NULL)
371         goto out;
372     }
373
374   current_owner = bus_service_get_primary_owner (service);
375
376   if (old_owner == NULL)
377     {
378       _dbus_assert (current_owner == connection);
379
380       bus_service_set_prohibit_replacement (service,
381                                             (flags & DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT));      
382                         
383       *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;      
384     }
385   else if (old_owner == connection)
386     *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
387   else if (!((flags & DBUS_NAME_FLAG_REPLACE_EXISTING)))
388     *result = DBUS_REQUEST_NAME_REPLY_EXISTS;
389   else if (bus_service_get_prohibit_replacement (service))
390     {
391       /* Queue the connection */
392       if (!bus_service_add_owner (service, connection,
393                                   transaction, error))
394         goto out;
395       
396       *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE;
397     }
398   else
399     {
400       /* Replace the current owner */
401
402       /* We enqueue the new owner and remove the first one because
403        * that will cause NameAcquired and NameLost messages to
404        * be sent.
405        */
406       
407       if (!bus_service_add_owner (service, connection,
408                                   transaction, error))
409         goto out;
410
411       if (!bus_service_remove_owner (service, old_owner,
412                                      transaction, error))
413         goto out;
414       
415       _dbus_assert (connection == bus_service_get_primary_owner (service));
416       *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
417     }
418
419   activation = bus_context_get_activation (registry->context);
420   retval = bus_activation_send_pending_auto_activation_messages (activation,
421                                                                  service,
422                                                                  transaction,
423                                                                  error);
424   
425  out:
426   return retval;
427 }
428
429 dbus_bool_t
430 bus_registry_set_service_context_table (BusRegistry   *registry,
431                                         DBusHashTable *table)
432 {
433   DBusHashTable *new_table;
434   DBusHashIter iter;
435   
436   new_table = bus_selinux_id_table_new ();
437   if (!new_table)
438     return FALSE;
439
440   _dbus_hash_iter_init (table, &iter);
441   while (_dbus_hash_iter_next (&iter))
442     {
443       const char *service = _dbus_hash_iter_get_string_key (&iter);
444       const char *context = _dbus_hash_iter_get_value (&iter);
445
446       if (!bus_selinux_id_table_insert (new_table,
447                                         service,
448                                         context))
449         return FALSE;
450     }
451   
452   if (registry->service_sid_table)
453     _dbus_hash_table_unref (registry->service_sid_table);
454   registry->service_sid_table = new_table;
455   return TRUE;
456 }
457
458 static void
459 bus_service_unlink_owner (BusService      *service,
460                           DBusConnection  *owner)
461 {
462   _dbus_list_remove_last (&service->owners, owner);
463   bus_connection_remove_owned_service (owner, service);
464 }
465
466 static void
467 bus_service_unlink (BusService *service)
468 {
469   _dbus_assert (service->owners == NULL);
470
471   /* the service may not be in the hash, if
472    * the failure causing transaction cancel
473    * was in the right place, but that's OK
474    */
475   _dbus_hash_table_remove_string (service->registry->service_hash,
476                                   service->name);
477   
478   bus_service_unref (service);
479 }
480
481 static void
482 bus_service_relink (BusService           *service,
483                     DBusPreallocatedHash *preallocated)
484 {
485   _dbus_assert (service->owners == NULL);
486   _dbus_assert (preallocated != NULL);
487
488   _dbus_hash_table_insert_string_preallocated (service->registry->service_hash,
489                                                preallocated,
490                                                service->name,
491                                                service);
492   
493   bus_service_ref (service);
494 }
495
496 /**
497  * Data used to represent an ownership cancellation in
498  * a bus transaction.
499  */
500 typedef struct
501 {
502   DBusConnection *connection; /**< the connection */
503   BusService *service;        /**< service to cancel ownership of */
504 } OwnershipCancelData;
505
506 static void
507 cancel_ownership (void *data)
508 {
509   OwnershipCancelData *d = data;
510
511   /* We don't need to send messages notifying of these
512    * changes, since we're reverting something that was
513    * cancelled (effectively never really happened)
514    */
515   bus_service_unlink_owner (d->service, d->connection);
516   
517   if (d->service->owners == NULL)
518     bus_service_unlink (d->service);
519 }
520
521 static void
522 free_ownership_cancel_data (void *data)
523 {
524   OwnershipCancelData *d = data;
525
526   dbus_connection_unref (d->connection);
527   bus_service_unref (d->service);
528   
529   dbus_free (d);
530 }
531
532 static dbus_bool_t
533 add_cancel_ownership_to_transaction (BusTransaction *transaction,
534                                      BusService     *service,
535                                      DBusConnection *connection)
536 {
537   OwnershipCancelData *d;
538
539   d = dbus_new (OwnershipCancelData, 1);
540   if (d == NULL)
541     return FALSE;
542   
543   d->service = service;
544   d->connection = connection;
545
546   if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d,
547                                         free_ownership_cancel_data))
548     {
549       dbus_free (d);
550       return FALSE;
551     }
552
553   bus_service_ref (d->service);
554   dbus_connection_ref (d->connection);
555   
556   return TRUE;
557 }
558
559 /* this function is self-cancelling if you cancel the transaction */
560 dbus_bool_t
561 bus_service_add_owner (BusService     *service,
562                        DBusConnection *owner,
563                        BusTransaction *transaction,
564                        DBusError      *error)
565 {
566   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
567   
568  /* Send service acquired message first, OOM will result
569   * in cancelling the transaction
570   */
571   if (service->owners == NULL)
572     {
573       if (!bus_driver_send_service_acquired (owner, service->name, transaction, error))
574         return FALSE;
575     }
576   
577   if (!_dbus_list_append (&service->owners,
578                           owner))
579     {
580       BUS_SET_OOM (error);
581       return FALSE;
582     }
583
584   if (!bus_connection_add_owned_service (owner, service))
585     {
586       _dbus_list_remove_last (&service->owners, owner);
587       BUS_SET_OOM (error);
588       return FALSE;
589     }
590
591   if (!add_cancel_ownership_to_transaction (transaction,
592                                             service,
593                                             owner))
594     {
595       bus_service_unlink_owner (service, owner);
596       BUS_SET_OOM (error);
597       return FALSE;
598     }
599   
600   return TRUE;
601 }
602
603 typedef struct
604 {
605   DBusConnection *connection;
606   BusService     *service;
607   DBusConnection *before_connection; /* restore to position before this connection in owners list */
608   DBusList       *connection_link;
609   DBusList       *service_link;
610   DBusPreallocatedHash *hash_entry;
611 } OwnershipRestoreData;
612
613 static void
614 restore_ownership (void *data)
615 {
616   OwnershipRestoreData *d = data;
617   DBusList *link;
618
619   _dbus_assert (d->service_link != NULL);
620   _dbus_assert (d->connection_link != NULL);
621   
622   if (d->service->owners == NULL)
623     {
624       _dbus_assert (d->hash_entry != NULL);
625       bus_service_relink (d->service, d->hash_entry);
626     }
627   else
628     {
629       _dbus_assert (d->hash_entry == NULL);
630     }
631   
632   /* We don't need to send messages notifying of these
633    * changes, since we're reverting something that was
634    * cancelled (effectively never really happened)
635    */
636   link = _dbus_list_get_first_link (&d->service->owners);
637   while (link != NULL)
638     {
639       if (link->data == d->before_connection)
640         break;
641
642       link = _dbus_list_get_next_link (&d->service->owners, link);
643     }
644   
645   _dbus_list_insert_before_link (&d->service->owners, link, d->connection_link);
646
647   /* Note that removing then restoring this changes the order in which
648    * ServiceDeleted messages are sent on destruction of the
649    * connection.  This should be OK as the only guarantee there is
650    * that the base service is destroyed last, and we never even
651    * tentatively remove the base service.
652    */
653   bus_connection_add_owned_service_link (d->connection, d->service_link);
654   
655   d->hash_entry = NULL;
656   d->service_link = NULL;
657   d->connection_link = NULL;
658 }
659
660 static void
661 free_ownership_restore_data (void *data)
662 {
663   OwnershipRestoreData *d = data;
664
665   if (d->service_link)
666     _dbus_list_free_link (d->service_link);
667   if (d->connection_link)
668     _dbus_list_free_link (d->connection_link);
669   if (d->hash_entry)
670     _dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash,
671                                               d->hash_entry);
672
673   dbus_connection_unref (d->connection);
674   bus_service_unref (d->service);
675   
676   dbus_free (d);
677 }
678
679 static dbus_bool_t
680 add_restore_ownership_to_transaction (BusTransaction *transaction,
681                                       BusService     *service,
682                                       DBusConnection *connection)
683 {
684   OwnershipRestoreData *d;
685   DBusList *link;
686
687   d = dbus_new (OwnershipRestoreData, 1);
688   if (d == NULL)
689     return FALSE;
690   
691   d->service = service;
692   d->connection = connection;
693   d->service_link = _dbus_list_alloc_link (service);
694   d->connection_link = _dbus_list_alloc_link (connection);
695   d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash);
696   
697   bus_service_ref (d->service);
698   dbus_connection_ref (d->connection);
699
700   d->before_connection = NULL;
701   link = _dbus_list_get_first_link (&service->owners);
702   while (link != NULL)
703     {
704       if (link->data == connection)
705         {
706           link = _dbus_list_get_next_link (&service->owners, link);
707
708           if (link)
709             d->before_connection = link->data;
710
711           break;
712         }
713       
714       link = _dbus_list_get_next_link (&service->owners, link);
715     }
716   
717   if (d->service_link == NULL ||
718       d->connection_link == NULL ||
719       d->hash_entry == NULL ||
720       !bus_transaction_add_cancel_hook (transaction, restore_ownership, d,
721                                         free_ownership_restore_data))
722     {
723       free_ownership_restore_data (d);
724       return FALSE;
725     }
726   
727   return TRUE;
728 }
729
730 /* this function is self-cancelling if you cancel the transaction */
731 dbus_bool_t
732 bus_service_remove_owner (BusService     *service,
733                           DBusConnection *owner,
734                           BusTransaction *transaction,
735                           DBusError      *error)
736 {
737   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
738   
739   /* We send out notifications before we do any work we
740    * might have to undo if the notification-sending failed
741    */
742   
743   /* Send service lost message */
744   if (bus_service_get_primary_owner (service) == owner)
745     {
746       if (!bus_driver_send_service_lost (owner, service->name,
747                                          transaction, error))
748         return FALSE;
749     }
750
751   if (service->owners == NULL)
752     {
753       _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners");
754     }
755   else if (_dbus_list_length_is_one (&service->owners))
756     {
757       if (!bus_driver_send_service_owner_changed (service->name,
758                                                   bus_connection_get_name (owner),
759                                                   NULL,
760                                                   transaction, error))
761         return FALSE;
762     }
763   else
764     {
765       DBusList *link;
766       DBusConnection *new_owner;
767       link = _dbus_list_get_first_link (&service->owners);
768       _dbus_assert (link != NULL);
769       link = _dbus_list_get_next_link (&service->owners, link);
770       _dbus_assert (link != NULL);
771
772       new_owner = link->data;
773
774       if (!bus_driver_send_service_owner_changed (service->name,
775                                                   bus_connection_get_name (owner),
776                                                   bus_connection_get_name (new_owner),
777                                                   transaction, error))
778         return FALSE;
779
780       /* This will be our new owner */
781       if (!bus_driver_send_service_acquired (new_owner,
782                                              service->name,
783                                              transaction,
784                                              error))
785         return FALSE;
786     }
787
788   if (!add_restore_ownership_to_transaction (transaction, service, owner))
789     {
790       BUS_SET_OOM (error);
791       return FALSE;
792     }
793   
794   bus_service_unlink_owner (service, owner);
795
796   if (service->owners == NULL)
797     bus_service_unlink (service);
798
799   return TRUE;
800 }
801
802 BusService *
803 bus_service_ref (BusService *service)
804 {
805   _dbus_assert (service->refcount > 0);
806   
807   service->refcount += 1;
808
809   return service;
810 }
811
812 void
813 bus_service_unref (BusService *service)
814 {
815   _dbus_assert (service->refcount > 0);
816   
817   service->refcount -= 1;
818
819   if (service->refcount == 0)
820     {
821       _dbus_assert (service->owners == NULL);
822       
823       dbus_free (service->name);
824       _dbus_mem_pool_dealloc (service->registry->service_pool, service);
825     }
826 }
827
828 DBusConnection*
829 bus_service_get_primary_owner (BusService *service)
830 {
831   return _dbus_list_get_first (&service->owners);
832 }
833
834 const char*
835 bus_service_get_name (BusService *service)
836 {
837   return service->name;
838 }
839
840 void
841 bus_service_set_prohibit_replacement (BusService  *service,
842                                       dbus_bool_t  prohibit_replacement)
843 {
844   service->prohibit_replacement = prohibit_replacement != FALSE;
845 }
846
847 dbus_bool_t
848 bus_service_get_prohibit_replacement (BusService *service)
849 {
850   return service->prohibit_replacement;
851 }
852
853 dbus_bool_t
854 bus_service_has_owner (BusService     *service,
855                        DBusConnection *owner)
856 {
857   DBusList *link;
858
859   link = _dbus_list_get_first_link (&service->owners);
860   
861   while (link != NULL)
862     {
863       if (link->data == owner)
864         return TRUE;
865       
866       link = _dbus_list_get_next_link (&service->owners, link);
867     }
868
869   return FALSE;
870 }