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