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