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