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