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 DBusConnection *current_owner_conn; 389 BusClientPolicy *policy; 390 BusService *service; 391 BusActivation *activation; 392 BusSELinuxID *sid; 393 BusOwner *primary_owner; 394 395 retval = FALSE; 396 397 if (!_dbus_validate_bus_name (service_name, 0, 398 _dbus_string_get_length (service_name))) 399 { 400 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, 401 "Requested bus name \"%s\" is not valid", 402 _dbus_string_get_const_data (service_name)); 403 404 _dbus_verbose ("Attempt to acquire invalid service name\n"); 405 406 goto out; 407 } 408 409 if (_dbus_string_get_byte (service_name, 0) == ':') 410 { 411 /* Not allowed; only base services can start with ':' */ 412 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, 413 "Cannot acquire a service starting with ':' such as \"%s\"", 414 _dbus_string_get_const_data (service_name)); 415 416 _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"", 417 _dbus_string_get_const_data (service_name)); 418 419 goto out; 420 } 421 422 if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) 423 { 424 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, 425 "Connection \"%s\" is not allowed to own the service \"%s\"because " 426 "it is reserved for D-Bus' use only", 427 bus_connection_is_active (connection) ? 428 bus_connection_get_name (connection) : 429 "(inactive)", 430 DBUS_SERVICE_DBUS); 431 goto out; 432 } 433 434 policy = bus_connection_get_policy (connection); 435 _dbus_assert (policy != NULL); 436 437 /* Note that if sid is #NULL then the bus's own context gets used 438 * in bus_connection_selinux_allows_acquire_service() 439 */ 440 sid = bus_selinux_id_table_lookup (registry->service_sid_table, 441 service_name); 442 443 if (!bus_selinux_allows_acquire_service (connection, sid, 444 _dbus_string_get_const_data (service_name), error)) 445 { 446 447 if (dbus_error_is_set (error) && 448 dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) 449 { 450 goto out; 451 } 452 453 dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, 454 "Connection \"%s\" is not allowed to own the service \"%s\" due " 455 "to SELinux policy", 456 bus_connection_is_active (connection) ? 457 bus_connection_get_name (connection) : 458 "(inactive)", 459 _dbus_string_get_const_data (service_name)); 460 goto out; 461 } 462 463 if (!bus_client_policy_check_can_own (policy, connection, 464 service_name)) 465 { 466 dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, 467 "Connection \"%s\" is not allowed to own the service \"%s\" due " 468 "to security policies in the configuration file", 469 bus_connection_is_active (connection) ? 470 bus_connection_get_name (connection) : 471 "(inactive)", 472 _dbus_string_get_const_data (service_name)); 473 goto out; 474 } 475 476 if (bus_connection_get_n_services_owned (connection) >= 477 bus_context_get_max_services_per_connection (registry->context)) 478 { 479 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, 480 "Connection \"%s\" is not allowed to own more services " 481 "(increase limits in configuration file if required)", 482 bus_connection_is_active (connection) ? 483 bus_connection_get_name (connection) : 484 "(inactive)"); 485 goto out; 486 } 487 488 service = bus_registry_lookup (registry, service_name); 489 490 if (service != NULL) 491 { 492 primary_owner = bus_service_get_primary_owner (service); 493 if (primary_owner != NULL) 494 old_owner_conn = primary_owner->conn; 495 else 496 old_owner_conn = NULL; 497 } 498 else 499 old_owner_conn = NULL; 500 501 if (service == NULL) 502 { 503 service = bus_registry_ensure (registry, 504 service_name, connection, flags, 505 transaction, error); 506 if (service == NULL) 507 goto out; 508 } 509 510 primary_owner = bus_service_get_primary_owner (service); 511 if (primary_owner == NULL) 512 goto out; 513 514 current_owner_conn = primary_owner->conn; 515 516 if (old_owner_conn == NULL) 517 { 518 _dbus_assert (current_owner_conn == connection); 519 520 *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; 521 } 522 else if (old_owner_conn == connection) 523 { 524 bus_owner_set_flags (primary_owner, flags); 525 *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; 526 } 527 else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && 528 !(bus_service_get_allow_replacement (service))) || 529 ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && 530 !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) 531 { 532 DBusList *link; 533 BusOwner *temp_owner; 534 /* Since we can't be queued if we are already in the queue 535 remove us */ 536 537 link = _bus_service_find_owner_link (service, connection); 538 if (link != NULL) 539 { 540 _dbus_list_unlink (&service->owners, link); 541 temp_owner = (BusOwner *)link->data; 542 bus_owner_unref (temp_owner); 543 _dbus_list_free_link (link); 544 } 545 546 *result = DBUS_REQUEST_NAME_REPLY_EXISTS; 547 } 548 else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && 549 (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || 550 !(bus_service_get_allow_replacement (service)))) 551 { 552 /* Queue the connection */ 553 if (!bus_service_add_owner (service, connection, 554 flags, 555 transaction, error)) 556 goto out; 557 558 *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE; 559 } 560 else 561 { 562 /* Replace the current owner */ 563 564 /* We enqueue the new owner and remove the first one because 565 * that will cause NameAcquired and NameLost messages to 566 * be sent. 567 */ 568 569 if (!bus_service_add_owner (service, connection, 570 flags, 571 transaction, error)) 572 goto out; 573 574 if (primary_owner->do_not_queue) 575 { 576 if (!bus_service_remove_owner (service, old_owner_conn, 577 transaction, error)) 578 goto out; 579 } 580 else 581 { 582 if (!bus_service_swap_owner (service, old_owner_conn, 583 transaction, error)) 584 goto out; 585 } 586 587 588 _dbus_assert (connection == bus_service_get_primary_owner (service)->conn); 589 *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; 590 } 591 592 activation = bus_context_get_activation (registry->context); 593 retval = bus_activation_send_pending_auto_activation_messages (activation, 594 service, 595 transaction, 596 error); 597 598 out: 599 return retval; 600 } 601 602 dbus_bool_t 603 bus_registry_release_service (BusRegistry *registry, 604 DBusConnection *connection, 605 const DBusString *service_name, 606 dbus_uint32_t *result, 607 BusTransaction *transaction, 608 DBusError *error) 609 { 610 dbus_bool_t retval; 611 BusService *service; 612 613 retval = FALSE; 614 615 if (!_dbus_validate_bus_name (service_name, 0, 616 _dbus_string_get_length (service_name))) 617 { 618 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, 619 "Given bus name \"%s\" is not valid", 620 _dbus_string_get_const_data (service_name)); 621 622 _dbus_verbose ("Attempt to release invalid service name\n"); 623 624 goto out; 625 } 626 627 if (_dbus_string_get_byte (service_name, 0) == ':') 628 { 629 /* Not allowed; the base service name cannot be created or released */ 630 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, 631 "Cannot release a service starting with ':' such as \"%s\"", 632 _dbus_string_get_const_data (service_name)); 633 634 _dbus_verbose ("Attempt to release invalid base service name \"%s\"", 635 _dbus_string_get_const_data (service_name)); 636 637 goto out; 638 } 639 640 if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) 641 { 642 /* Not allowed; the base service name cannot be created or released */ 643 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, 644 "Cannot release the %s service because it is owned by the bus", 645 DBUS_SERVICE_DBUS); 646 647 _dbus_verbose ("Attempt to release service name \"%s\"", 648 DBUS_SERVICE_DBUS); 649 650 goto out; 651 } 652 653 service = bus_registry_lookup (registry, service_name); 654 655 if (service == NULL) 656 { 657 *result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT; 658 } 659 else if (!bus_service_has_owner (service, connection)) 660 { 661 *result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER; 662 } 663 else 664 { 665 if (!bus_service_remove_owner (service, connection, 666 transaction, error)) 667 goto out; 668 669 _dbus_assert (!bus_service_has_owner (service, connection)); 670 *result = DBUS_RELEASE_NAME_REPLY_RELEASED; 671 } 672 673 retval = TRUE; 674 675 out: 676 return retval; 677 } 678 679 dbus_bool_t 680 bus_registry_set_service_context_table (BusRegistry *registry, 681 DBusHashTable *table) 682 { 683 DBusHashTable *new_table; 684 DBusHashIter iter; 685 686 new_table = bus_selinux_id_table_new (); 687 if (!new_table) 688 return FALSE; 689 690 _dbus_hash_iter_init (table, &iter); 691 while (_dbus_hash_iter_next (&iter)) 692 { 693 const char *service = _dbus_hash_iter_get_string_key (&iter); 694 const char *context = _dbus_hash_iter_get_value (&iter); 695 696 if (!bus_selinux_id_table_insert (new_table, 697 service, 698 context)) 699 return FALSE; 700 } 701 702 if (registry->service_sid_table) 703 _dbus_hash_table_unref (registry->service_sid_table); 704 registry->service_sid_table = new_table; 705 return TRUE; 706 } 707 708 static void 709 bus_service_unlink_owner (BusService *service, 710 BusOwner *owner) 711 { 712 _dbus_list_remove_last (&service->owners, owner); 713 bus_owner_unref (owner); 714 } 715 716 static void 717 bus_service_unlink (BusService *service) 718 { 719 _dbus_assert (service->owners == NULL); 720 721 /* the service may not be in the hash, if 722 * the failure causing transaction cancel 723 * was in the right place, but that's OK 724 */ 725 _dbus_hash_table_remove_string (service->registry->service_hash, 726 service->name); 727 728 bus_service_unref (service); 729 } 730 731 static void 732 bus_service_relink (BusService *service, 733 DBusPreallocatedHash *preallocated) 734 { 735 _dbus_assert (service->owners == NULL); 736 _dbus_assert (preallocated != NULL); 737 738 _dbus_hash_table_insert_string_preallocated (service->registry->service_hash, 739 preallocated, 740 service->name, 741 service); 742 743 bus_service_ref (service); 744 } 745 746 /** 747 * Data used to represent an ownership cancellation in 748 * a bus transaction. 749 */ 750 typedef struct 751 { 752 BusOwner *owner; /**< the owner */ 753 BusService *service; /**< service to cancel ownership of */ 754 } OwnershipCancelData; 755 756 static void 757 cancel_ownership (void *data) 758 { 759 OwnershipCancelData *d = data; 760 761 /* We don't need to send messages notifying of these 762 * changes, since we're reverting something that was 763 * cancelled (effectively never really happened) 764 */ 765 bus_service_unlink_owner (d->service, d->owner); 766 767 if (d->service->owners == NULL) 768 bus_service_unlink (d->service); 769 } 770 771 static void 772 free_ownership_cancel_data (void *data) 773 { 774 OwnershipCancelData *d = data; 775 776 dbus_connection_unref (d->owner->conn); 777 bus_owner_unref (d->owner); 778 bus_service_unref (d->service); 779 780 dbus_free (d); 781 } 782 783 static dbus_bool_t 784 add_cancel_ownership_to_transaction (BusTransaction *transaction, 785 BusService *service, 786 BusOwner *owner) 787 { 788 OwnershipCancelData *d; 789 790 d = dbus_new (OwnershipCancelData, 1); 791 if (d == NULL) 792 return FALSE; 793 794 d->service = service; 795 d->owner = owner; 796 797 if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d, 798 free_ownership_cancel_data)) 799 { 800 dbus_free (d); 801 return FALSE; 802 } 803 804 bus_service_ref (d->service); 805 bus_owner_ref (owner); 806 dbus_connection_ref (d->owner->conn); 807 808 return TRUE; 809 } 810 811 /* this function is self-cancelling if you cancel the transaction */ 812 dbus_bool_t 813 bus_service_add_owner (BusService *service, 814 DBusConnection *connection, 815 dbus_uint32_t flags, 816 BusTransaction *transaction, 817 DBusError *error) 818 { 819 BusOwner *bus_owner; 820 DBusList *bus_owner_link; 821 822 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 823 824 /* Send service acquired message first, OOM will result 825 * in cancelling the transaction 826 */ 827 if (service->owners == NULL) 828 { 829 if (!bus_driver_send_service_acquired (connection, service->name, transaction, error)) 830 return FALSE; 831 } 832 833 bus_owner_link = _bus_service_find_owner_link (service, connection); 834 835 if (bus_owner_link == NULL) 836 { 837 bus_owner = bus_owner_new (service, connection, flags); 838 if (bus_owner == NULL) 839 { 840 BUS_SET_OOM (error); 841 return FALSE; 842 } 843 844 bus_owner_set_flags (bus_owner, flags); 845 if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL) 846 { 847 if (!_dbus_list_append (&service->owners, 848 bus_owner)) 849 { 850 bus_owner_unref (bus_owner); 851 BUS_SET_OOM (error); 852 return FALSE; 853 } 854 } 855 else 856 { 857 if (!_dbus_list_insert_after (&service->owners, 858 _dbus_list_get_first_link (&service->owners), 859 bus_owner)) 860 { 861 bus_owner_unref (bus_owner); 862 BUS_SET_OOM (error); 863 return FALSE; 864 } 865 } 866 } 867 else 868 { 869 /* Update the link since we are already in the queue 870 * No need for operations that can produce OOM 871 */ 872 873 bus_owner = (BusOwner *) bus_owner_link->data; 874 if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING) 875 { 876 DBusList *link; 877 _dbus_list_unlink (&service->owners, bus_owner_link); 878 link = _dbus_list_get_first_link (&service->owners); 879 _dbus_assert (link != NULL); 880 881 _dbus_list_insert_after_link (&service->owners, link, bus_owner_link); 882 } 883 884 bus_owner_set_flags (bus_owner, flags); 885 return TRUE; 886 } 887 888 if (!add_cancel_ownership_to_transaction (transaction, 889 service, 890 bus_owner)) 891 { 892 bus_service_unlink_owner (service, bus_owner); 893 BUS_SET_OOM (error); 894 return FALSE; 895 } 896 897 return TRUE; 898 } 899 900 typedef struct 901 { 902 BusOwner *owner; 903 BusService *service; 904 BusOwner *before_owner; /* restore to position before this connection in owners list */ 905 DBusList *owner_link; 906 DBusList *service_link; 907 DBusPreallocatedHash *hash_entry; 908 } OwnershipRestoreData; 909 910 static void 911 restore_ownership (void *data) 912 { 913 OwnershipRestoreData *d = data; 914 DBusList *link; 915 916 _dbus_assert (d->service_link != NULL); 917 _dbus_assert (d->owner_link != NULL); 918 919 if (d->service->owners == NULL) 920 { 921 _dbus_assert (d->hash_entry != NULL); 922 bus_service_relink (d->service, d->hash_entry); 923 } 924 else 925 { 926 _dbus_assert (d->hash_entry == NULL); 927 } 928 929 /* We don't need to send messages notifying of these 930 * changes, since we're reverting something that was 931 * cancelled (effectively never really happened) 932 */ 933 link = _dbus_list_get_first_link (&d->service->owners); 934 while (link != NULL) 935 { 936 if (link->data == d->before_owner) 937 break; 938 939 link = _dbus_list_get_next_link (&d->service->owners, link); 940 } 941 942 _dbus_list_insert_before_link (&d->service->owners, link, d->owner_link); 943 944 /* Note that removing then restoring this changes the order in which 945 * ServiceDeleted messages are sent on destruction of the 946 * connection. This should be OK as the only guarantee there is 947 * that the base service is destroyed last, and we never even 948 * tentatively remove the base service. 949 */ 950 bus_connection_add_owned_service_link (d->owner->conn, d->service_link); 951 952 d->hash_entry = NULL; 953 d->service_link = NULL; 954 d->owner_link = NULL; 955 } 956 957 static void 958 free_ownership_restore_data (void *data) 959 { 960 OwnershipRestoreData *d = data; 961 962 if (d->service_link) 963 _dbus_list_free_link (d->service_link); 964 if (d->owner_link) 965 _dbus_list_free_link (d->owner_link); 966 if (d->hash_entry) 967 _dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash, 968 d->hash_entry); 969 970 dbus_connection_unref (d->owner->conn); 971 bus_owner_unref (d->owner); 972 bus_service_unref (d->service); 973 974 dbus_free (d); 975 } 976 977 static dbus_bool_t 978 add_restore_ownership_to_transaction (BusTransaction *transaction, 979 BusService *service, 980 BusOwner *owner) 981 { 982 OwnershipRestoreData *d; 983 DBusList *link; 984 985 d = dbus_new (OwnershipRestoreData, 1); 986 if (d == NULL) 987 return FALSE; 988 989 d->service = service; 990 d->owner = owner; 991 d->service_link = _dbus_list_alloc_link (service); 992 d->owner_link = _dbus_list_alloc_link (owner); 993 d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash); 994 995 bus_service_ref (d->service); 996 bus_owner_ref (d->owner); 997 dbus_connection_ref (d->owner->conn); 998 999 d->before_owner = NULL; 1000 link = _dbus_list_get_first_link (&service->owners); 1001 while (link != NULL) 1002 { 1003 if (link->data == owner) 1004 { 1005 link = _dbus_list_get_next_link (&service->owners, link); 1006 1007 if (link) 1008 d->before_owner = link->data; 1009 1010 break; 1011 } 1012 1013 link = _dbus_list_get_next_link (&service->owners, link); 1014 } 1015 1016 if (d->service_link == NULL || 1017 d->owner_link == NULL || 1018 d->hash_entry == NULL || 1019 !bus_transaction_add_cancel_hook (transaction, restore_ownership, d, 1020 free_ownership_restore_data)) 1021 { 1022 free_ownership_restore_data (d); 1023 return FALSE; 1024 } 1025 1026 return TRUE; 1027 } 1028 1029 dbus_bool_t 1030 bus_service_swap_owner (BusService *service, 1031 DBusConnection *connection, 1032 BusTransaction *transaction, 1033 DBusError *error) 1034 { 1035 DBusList *swap_link; 1036 BusOwner *primary_owner; 1037 1038 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 1039 1040 /* We send out notifications before we do any work we 1041 * might have to undo if the notification-sending failed 1042 */ 1043 1044 /* Send service lost message */ 1045 primary_owner = bus_service_get_primary_owner (service); 1046 if (primary_owner == NULL || primary_owner->conn != connection) 1047 _dbus_assert_not_reached ("Tried to swap a non primary owner"); 1048 1049 1050 if (!bus_driver_send_service_lost (connection, service->name, 1051 transaction, error)) 1052 return FALSE; 1053 1054 if (service->owners == NULL) 1055 { 1056 _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners"); 1057 } 1058 else if (_dbus_list_length_is_one (&service->owners)) 1059 { 1060 _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue"); 1061 } 1062 else 1063 { 1064 DBusList *link; 1065 BusOwner *new_owner; 1066 DBusConnection *new_owner_conn; 1067 link = _dbus_list_get_first_link (&service->owners); 1068 _dbus_assert (link != NULL); 1069 link = _dbus_list_get_next_link (&service->owners, link); 1070 _dbus_assert (link != NULL); 1071 1072 new_owner = (BusOwner *)link->data; 1073 new_owner_conn = new_owner->conn; 1074 1075 if (!bus_driver_send_service_owner_changed (service->name, 1076 bus_connection_get_name (connection), 1077 bus_connection_get_name (new_owner_conn), 1078 transaction, error)) 1079 return FALSE; 1080 1081 /* This will be our new owner */ 1082 if (!bus_driver_send_service_acquired (new_owner_conn, 1083 service->name, 1084 transaction, 1085 error)) 1086 return FALSE; 1087 } 1088 1089 if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) 1090 { 1091 BUS_SET_OOM (error); 1092 return FALSE; 1093 } 1094 1095 /* unlink the primary and make it the second link */ 1096 swap_link = _dbus_list_get_first_link (&service->owners); 1097 _dbus_list_unlink (&service->owners, swap_link); 1098 1099 _dbus_list_insert_after_link (&service->owners, 1100 _dbus_list_get_first_link (&service->owners), 1101 swap_link); 1102 1103 return TRUE; 1104 } 1105 1106 /* this function is self-cancelling if you cancel the transaction */ 1107 dbus_bool_t 1108 bus_service_remove_owner (BusService *service, 1109 DBusConnection *connection, 1110 BusTransaction *transaction, 1111 DBusError *error) 1112 { 1113 BusOwner *primary_owner; 1114 1115 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 1116 1117 /* We send out notifications before we do any work we 1118 * might have to undo if the notification-sending failed 1119 */ 1120 1121 /* Send service lost message */ 1122 primary_owner = bus_service_get_primary_owner (service); 1123 if (primary_owner != NULL && primary_owner->conn == connection) 1124 { 1125 if (!bus_driver_send_service_lost (connection, service->name, 1126 transaction, error)) 1127 return FALSE; 1128 } 1129 else 1130 { 1131 /* if we are not the primary owner then just remove us from the queue */ 1132 DBusList *link; 1133 BusOwner *temp_owner; 1134 1135 link = _bus_service_find_owner_link (service, connection); 1136 _dbus_list_unlink (&service->owners, link); 1137 temp_owner = (BusOwner *)link->data; 1138 bus_owner_unref (temp_owner); 1139 _dbus_list_free_link (link); 1140 1141 return TRUE; 1142 } 1143 1144 if (service->owners == NULL) 1145 { 1146 _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners"); 1147 } 1148 else if (_dbus_list_length_is_one (&service->owners)) 1149 { 1150 if (!bus_driver_send_service_owner_changed (service->name, 1151 bus_connection_get_name (connection), 1152 NULL, 1153 transaction, error)) 1154 return FALSE; 1155 } 1156 else 1157 { 1158 DBusList *link; 1159 BusOwner *new_owner; 1160 DBusConnection *new_owner_conn; 1161 link = _dbus_list_get_first_link (&service->owners); 1162 _dbus_assert (link != NULL); 1163 link = _dbus_list_get_next_link (&service->owners, link); 1164 _dbus_assert (link != NULL); 1165 1166 new_owner = (BusOwner *)link->data; 1167 new_owner_conn = new_owner->conn; 1168 1169 if (!bus_driver_send_service_owner_changed (service->name, 1170 bus_connection_get_name (connection), 1171 bus_connection_get_name (new_owner_conn), 1172 transaction, error)) 1173 return FALSE; 1174 1175 /* This will be our new owner */ 1176 if (!bus_driver_send_service_acquired (new_owner_conn, 1177 service->name, 1178 transaction, 1179 error)) 1180 return FALSE; 1181 } 1182 1183 if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) 1184 { 1185 BUS_SET_OOM (error); 1186 return FALSE; 1187 } 1188 1189 bus_service_unlink_owner (service, primary_owner); 1190 1191 if (service->owners == NULL) 1192 bus_service_unlink (service); 1193 1194 return TRUE; 1195 } 1196 1197 BusService * 1198 bus_service_ref (BusService *service) 1199 { 1200 _dbus_assert (service->refcount > 0); 1201 1202 service->refcount += 1; 1203 1204 return service; 1205 } 1206 1207 void 1208 bus_service_unref (BusService *service) 1209 { 1210 _dbus_assert (service->refcount > 0); 1211 1212 service->refcount -= 1; 1213 1214 if (service->refcount == 0) 1215 { 1216 _dbus_assert (service->owners == NULL); 1217 1218 dbus_free (service->name); 1219 _dbus_mem_pool_dealloc (service->registry->service_pool, service); 1220 } 1221 } 1222 1223 DBusConnection * 1224 bus_service_get_primary_owners_connection (BusService *service) 1225 { 1226 BusOwner *owner; 1227 1228 owner = bus_service_get_primary_owner (service); 1229 1230 if (owner != NULL) 1231 return owner->conn; 1232 else 1233 return NULL; 1234 } 1235 1236 BusOwner* 1237 bus_service_get_primary_owner (BusService *service) 1238 { 1239 return _dbus_list_get_first (&service->owners); 1240 } 1241 1242 const char* 1243 bus_service_get_name (BusService *service) 1244 { 1245 return service->name; 1246 } 1247 1248 dbus_bool_t 1249 bus_service_get_allow_replacement (BusService *service) 1250 { 1251 BusOwner *owner; 1252 DBusList *link; 1253 1254 _dbus_assert (service->owners != NULL); 1255 1256 link = _dbus_list_get_first_link (&service->owners); 1257 owner = (BusOwner *) link->data; 1258 1259 return owner->allow_replacement; 1260 } 1261 1262 dbus_bool_t 1263 bus_service_has_owner (BusService *service, 1264 DBusConnection *connection) 1265 { 1266 DBusList *link; 1267 1268 link = _bus_service_find_owner_link (service, connection); 1269 1270 if (link == NULL) 1271 return FALSE; 1272 else 1273 return TRUE; 1274 } 1275 1276 dbus_bool_t 1277 bus_service_list_queued_owners (BusService *service, 1278 DBusList **return_list, 1279 DBusError *error) 1280 { 1281 DBusList *link; 1282 1283 _dbus_assert (*return_list == NULL); 1284 1285 link = _dbus_list_get_first_link (&service->owners); 1286 _dbus_assert (link != NULL); 1287 1288 while (link != NULL) 1289 { 1290 BusOwner *owner; 1291 const char *uname; 1292 1293 owner = (BusOwner *) link->data; 1294 uname = bus_connection_get_name (owner->conn); 1295 1296 if (!_dbus_list_append (return_list, (char *)uname)) 1297 goto oom; 1298 1299 link = _dbus_list_get_next_link (&service->owners, link); 1300 } 1301 1302 return TRUE; 1303 1304 oom: 1305 _dbus_list_clear (return_list); 1306 BUS_SET_OOM (error); 1307 return FALSE; 1308 } 1309