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* 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 * 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 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* 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 * 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 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 * 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 * 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 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* 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 * 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* 1233 bus_service_get_primary_owner (BusService *service) 1234 { 1235 return _dbus_list_get_first (&service->owners); 1236 } 1237 1238 const char* 1239 bus_service_get_name (BusService *service) 1240 { 1241 return service->name; 1242 } 1243 1244 dbus_bool_t 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 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 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