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