1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* dbus-transport.c DBusTransport object (internal to D-Bus implementation) 3 * 4 * Copyright (C) 2002, 2003 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include "dbus-transport-protected.h" 25 #include "dbus-transport-unix.h" 26 #include "dbus-transport-socket.h" 27 #include "dbus-connection-internal.h" 28 #include "dbus-watch.h" 29 #include "dbus-auth.h" 30 #include "dbus-address.h" 31 #ifdef DBUS_BUILD_TESTS 32 #include "dbus-server-debug-pipe.h" 33 #endif 34 35 /** 36 * @defgroup DBusTransport DBusTransport object 37 * @ingroup DBusInternals 38 * @brief "Backend" for a DBusConnection. 39 * 40 * Types and functions related to DBusTransport. A transport is an 41 * abstraction that can send and receive data via various kinds of 42 * network connections or other IPC mechanisms. 43 * 44 * @{ 45 */ 46 47 /** 48 * @typedef DBusTransport 49 * 50 * Opaque object representing a way message stream. 51 * DBusTransport abstracts various kinds of actual 52 * transport mechanism, such as different network protocols, 53 * or encryption schemes. 54 */ 55 56 static void 57 live_messages_size_notify (DBusCounter *counter, 58 void *user_data) 59 { 60 DBusTransport *transport = user_data; 61 62 _dbus_transport_ref (transport); 63 64 #if 0 65 _dbus_verbose ("Counter value is now %d\n", 66 (int) _dbus_counter_get_value (counter)); 67 #endif 68 69 /* disable or re-enable the read watch for the transport if 70 * required. 71 */ 72 if (transport->vtable->live_messages_changed) 73 (* transport->vtable->live_messages_changed) (transport); 74 75 _dbus_transport_unref (transport); 76 } 77 78 /** 79 * Initializes the base class members of DBusTransport. Chained up to 80 * by subclasses in their constructor. The server GUID is the 81 * globally unique ID for the server creating this connection 82 * and will be #NULL for the client side of a connection. The GUID 83 * is in hex format. 84 * 85 * @param transport the transport being created. 86 * @param vtable the subclass vtable. 87 * @param server_guid non-#NULL if this transport is on the server side of a connection 88 * @param address the address of the transport 89 * @returns #TRUE on success. 90 */ 91 dbus_bool_t 92 _dbus_transport_init_base (DBusTransport *transport, 93 const DBusTransportVTable *vtable, 94 const DBusString *server_guid, 95 const DBusString *address) 96 { 97 DBusMessageLoader *loader; 98 DBusAuth *auth; 99 DBusCounter *counter; 100 char *address_copy; 101 102 loader = _dbus_message_loader_new (); 103 if (loader == NULL) 104 return FALSE; 105 106 if (server_guid) 107 auth = _dbus_auth_server_new (server_guid); 108 else 109 auth = _dbus_auth_client_new (); 110 if (auth == NULL) 111 { 112 _dbus_message_loader_unref (loader); 113 return FALSE; 114 } 115 116 counter = _dbus_counter_new (); 117 if (counter == NULL) 118 { 119 _dbus_auth_unref (auth); 120 _dbus_message_loader_unref (loader); 121 return FALSE; 122 } 123 124 if (server_guid) 125 { 126 _dbus_assert (address == NULL); 127 address_copy = NULL; 128 } 129 else 130 { 131 _dbus_assert (address != NULL); 132 133 if (!_dbus_string_copy_data (address, &address_copy)) 134 { 135 _dbus_counter_unref (counter); 136 _dbus_auth_unref (auth); 137 _dbus_message_loader_unref (loader); 138 return FALSE; 139 } 140 } 141 142 transport->refcount = 1; 143 transport->vtable = vtable; 144 transport->loader = loader; 145 transport->auth = auth; 146 transport->live_messages_size = counter; 147 transport->authenticated = FALSE; 148 transport->disconnected = FALSE; 149 transport->is_server = (server_guid != NULL); 150 transport->send_credentials_pending = !transport->is_server; 151 transport->receive_credentials_pending = transport->is_server; 152 transport->address = address_copy; 153 154 transport->unix_user_function = NULL; 155 transport->unix_user_data = NULL; 156 transport->free_unix_user_data = NULL; 157 158 transport->expected_guid = NULL; 159 160 /* Try to default to something that won't totally hose the system, 161 * but doesn't impose too much of a limitation. 162 */ 163 transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63; 164 165 transport->credentials.pid = -1; 166 transport->credentials.uid = -1; 167 transport->credentials.gid = -1; 168 169 _dbus_counter_set_notify (transport->live_messages_size, 170 transport->max_live_messages_size, 171 live_messages_size_notify, 172 transport); 173 174 if (transport->address) 175 _dbus_verbose ("Initialized transport on address %s\n", transport->address); 176 177 return TRUE; 178 } 179 180 /** 181 * Finalizes base class members of DBusTransport. 182 * Chained up to from subclass finalizers. 183 * 184 * @param transport the transport. 185 */ 186 void 187 _dbus_transport_finalize_base (DBusTransport *transport) 188 { 189 if (!transport->disconnected) 190 _dbus_transport_disconnect (transport); 191 192 if (transport->free_unix_user_data != NULL) 193 (* transport->free_unix_user_data) (transport->unix_user_data); 194 195 _dbus_message_loader_unref (transport->loader); 196 _dbus_auth_unref (transport->auth); 197 _dbus_counter_set_notify (transport->live_messages_size, 198 0, NULL, NULL); 199 _dbus_counter_unref (transport->live_messages_size); 200 dbus_free (transport->address); 201 dbus_free (transport->expected_guid); 202 } 203 204 205 /** 206 * Verifies if a given D-Bus address is a valid address 207 * by attempting to connect to it. If it is, returns the 208 * opened DBusTransport object. If it isn't, returns #NULL 209 * and sets @p error. 210 * 211 * @param error address where an error can be returned. 212 * @returns a new transport, or #NULL on failure. 213 */ 214 static DBusTransport* 215 check_address (const char *address, DBusError *error) 216 { 217 DBusAddressEntry **entries; 218 DBusTransport *transport = NULL; 219 int len, i; 220 221 _dbus_assert (address != NULL); 222 _dbus_assert (*address != '\0'); 223 224 if (!dbus_parse_address (address, &entries, &len, error)) 225 return FALSE; /* not a valid address */ 226 227 for (i = 0; i < len; i++) 228 { 229 transport = _dbus_transport_open (entries[i], error); 230 if (transport != NULL) 231 break; 232 } 233 234 dbus_address_entries_free (entries); 235 return transport; 236 } 237 238 /** 239 * Creates a new transport for the "autostart" method. 240 * This creates a client-side of a transport. 241 * 242 * @param error address where an error can be returned. 243 * @returns a new transport, or #NULL on failure. 244 */ 245 static DBusTransport* 246 _dbus_transport_new_for_autolaunch (DBusError *error) 247 { 248 DBusString address; 249 DBusTransport *result = NULL; 250 251 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 252 253 if (!_dbus_string_init (&address)) 254 { 255 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 256 return NULL; 257 } 258 259 if (!_dbus_get_autolaunch_address (&address, error)) 260 { 261 _DBUS_ASSERT_ERROR_IS_SET (error); 262 goto out; 263 } 264 265 result = check_address (_dbus_string_get_const_data (&address), error); 266 if (result == NULL) 267 _DBUS_ASSERT_ERROR_IS_SET (error); 268 else 269 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 270 271 out: 272 _dbus_string_free (&address); 273 return result; 274 } 275 276 static DBusTransportOpenResult 277 _dbus_transport_open_autolaunch (DBusAddressEntry *entry, 278 DBusTransport **transport_p, 279 DBusError *error) 280 { 281 const char *method; 282 283 method = dbus_address_entry_get_method (entry); 284 _dbus_assert (method != NULL); 285 286 if (strcmp (method, "autolaunch") == 0) 287 { 288 *transport_p = _dbus_transport_new_for_autolaunch (error); 289 290 if (*transport_p == NULL) 291 { 292 _DBUS_ASSERT_ERROR_IS_SET (error); 293 return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; 294 } 295 else 296 { 297 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 298 return DBUS_TRANSPORT_OPEN_OK; 299 } 300 } 301 else 302 { 303 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 304 return DBUS_TRANSPORT_OPEN_NOT_HANDLED; 305 } 306 } 307 308 static const struct { 309 DBusTransportOpenResult (* func) (DBusAddressEntry *entry, 310 DBusTransport **transport_p, 311 DBusError *error); 312 } open_funcs[] = { 313 { _dbus_transport_open_socket }, 314 { _dbus_transport_open_platform_specific }, 315 { _dbus_transport_open_autolaunch } 316 #ifdef DBUS_BUILD_TESTS 317 , { _dbus_transport_open_debug_pipe } 318 #endif 319 }; 320 321 /** 322 * Try to open a new transport for the given address entry. (This 323 * opens a client-side-of-the-connection transport.) 324 * 325 * @param entry the address entry 326 * @param error location to store reason for failure. 327 * @returns new transport of #NULL on failure. 328 */ 329 DBusTransport* 330 _dbus_transport_open (DBusAddressEntry *entry, 331 DBusError *error) 332 { 333 DBusTransport *transport; 334 const char *expected_guid_orig; 335 char *expected_guid; 336 int i; 337 DBusError tmp_error; 338 339 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 340 341 transport = NULL; 342 expected_guid_orig = dbus_address_entry_get_value (entry, "guid"); 343 expected_guid = _dbus_strdup (expected_guid_orig); 344 345 if (expected_guid_orig != NULL && expected_guid == NULL) 346 { 347 _DBUS_SET_OOM (error); 348 return NULL; 349 } 350 351 dbus_error_init (&tmp_error); 352 for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i) 353 { 354 DBusTransportOpenResult result; 355 356 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); 357 result = (* open_funcs[i].func) (entry, &transport, &tmp_error); 358 359 switch (result) 360 { 361 case DBUS_TRANSPORT_OPEN_OK: 362 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); 363 goto out; 364 break; 365 case DBUS_TRANSPORT_OPEN_NOT_HANDLED: 366 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); 367 /* keep going through the loop of open funcs */ 368 break; 369 case DBUS_TRANSPORT_OPEN_BAD_ADDRESS: 370 _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); 371 goto out; 372 break; 373 case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT: 374 _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); 375 goto out; 376 break; 377 } 378 } 379 380 out: 381 382 if (transport == NULL) 383 { 384 if (!dbus_error_is_set (&tmp_error)) 385 _dbus_set_bad_address (&tmp_error, 386 NULL, NULL, 387 "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")"); 388 389 _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); 390 dbus_move_error(&tmp_error, error); 391 dbus_free (expected_guid); 392 } 393 else 394 { 395 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); 396 transport->expected_guid = expected_guid; 397 } 398 399 return transport; 400 } 401 402 /** 403 * Increments the reference count for the transport. 404 * 405 * @param transport the transport. 406 * @returns the transport. 407 */ 408 DBusTransport * 409 _dbus_transport_ref (DBusTransport *transport) 410 { 411 _dbus_assert (transport->refcount > 0); 412 413 transport->refcount += 1; 414 415 return transport; 416 } 417 418 /** 419 * Decrements the reference count for the transport. 420 * Disconnects and finalizes the transport if 421 * the reference count reaches zero. 422 * 423 * @param transport the transport. 424 */ 425 void 426 _dbus_transport_unref (DBusTransport *transport) 427 { 428 _dbus_assert (transport != NULL); 429 _dbus_assert (transport->refcount > 0); 430 431 transport->refcount -= 1; 432 if (transport->refcount == 0) 433 { 434 _dbus_verbose ("%s: finalizing\n", _DBUS_FUNCTION_NAME); 435 436 _dbus_assert (transport->vtable->finalize != NULL); 437 438 (* transport->vtable->finalize) (transport); 439 } 440 } 441 442 /** 443 * Closes our end of the connection to a remote application. Further 444 * attempts to use this transport will fail. Only the first call to 445 * _dbus_transport_disconnect() will have an effect. 446 * 447 * @param transport the transport. 448 * 449 */ 450 void 451 _dbus_transport_disconnect (DBusTransport *transport) 452 { 453 _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); 454 455 _dbus_assert (transport->vtable->disconnect != NULL); 456 457 if (transport->disconnected) 458 return; 459 460 (* transport->vtable->disconnect) (transport); 461 462 transport->disconnected = TRUE; 463 464 _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); 465 } 466 467 /** 468 * Returns #TRUE if the transport has not been disconnected. 469 * Disconnection can result from _dbus_transport_disconnect() 470 * or because the server drops its end of the connection. 471 * 472 * @param transport the transport. 473 * @returns whether we're connected 474 */ 475 dbus_bool_t 476 _dbus_transport_get_is_connected (DBusTransport *transport) 477 { 478 return !transport->disconnected; 479 } 480 481 /** 482 * Returns #TRUE if we have been authenticated. Will return #TRUE 483 * even if the transport is disconnected. 484 * 485 * @todo we drop connection->mutex when calling the unix_user_function, 486 * which may not be safe really. 487 * 488 * @param transport the transport 489 * @returns whether we're authenticated 490 */ 491 dbus_bool_t 492 _dbus_transport_get_is_authenticated (DBusTransport *transport) 493 { 494 /* We don't want to run unix_user_function on Windows, but it 495 * can exist, which allows application code to just unconditionally 496 * set it and have it only be invoked when appropriate. 497 */ 498 dbus_bool_t on_windows = FALSE; 499 #ifdef DBUS_WIN 500 on_windows = TRUE; 501 #endif 502 503 if (transport->authenticated) 504 return TRUE; 505 else 506 { 507 dbus_bool_t maybe_authenticated; 508 509 if (transport->disconnected) 510 return FALSE; 511 512 /* paranoia ref since we call user callbacks sometimes */ 513 _dbus_connection_ref_unlocked (transport->connection); 514 515 maybe_authenticated = 516 (!(transport->send_credentials_pending || 517 transport->receive_credentials_pending)); 518 519 if (maybe_authenticated) 520 { 521 switch (_dbus_auth_do_work (transport->auth)) 522 { 523 case DBUS_AUTH_STATE_AUTHENTICATED: 524 /* leave as maybe_authenticated */ 525 break; 526 default: 527 maybe_authenticated = FALSE; 528 } 529 } 530 531 if (maybe_authenticated && !transport->is_server) 532 { 533 const char *server_guid; 534 535 server_guid = _dbus_auth_get_guid_from_server (transport->auth); 536 _dbus_assert (server_guid != NULL); 537 538 if (transport->expected_guid && 539 strcmp (transport->expected_guid, server_guid) != 0) 540 { 541 _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n", 542 transport->expected_guid, server_guid); 543 _dbus_transport_disconnect (transport); 544 _dbus_connection_unref_unlocked (transport->connection); 545 return FALSE; 546 } 547 548 if (transport->expected_guid == NULL) 549 { 550 transport->expected_guid = _dbus_strdup (server_guid); 551 552 if (transport->expected_guid == NULL) 553 { 554 _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME); 555 return FALSE; 556 } 557 } 558 } 559 560 /* If we've authenticated as some identity, check that the auth 561 * identity is the same as our own identity. In the future, we 562 * may have API allowing applications to specify how this is 563 * done, for example they may allow connection as any identity, 564 * but then impose restrictions on certain identities. 565 * Or they may give certain identities extra privileges. 566 */ 567 568 if (maybe_authenticated && transport->is_server) 569 { 570 DBusCredentials auth_identity; 571 572 _dbus_auth_get_identity (transport->auth, &auth_identity); 573 574 if (transport->unix_user_function != NULL && !on_windows) 575 { 576 dbus_bool_t allow; 577 DBusConnection *connection; 578 DBusAllowUnixUserFunction unix_user_function; 579 void *unix_user_data; 580 581 /* Dropping the lock here probably isn't that safe. */ 582 583 connection = transport->connection; 584 unix_user_function = transport->unix_user_function; 585 unix_user_data = transport->unix_user_data; 586 587 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 588 _dbus_connection_unlock (connection); 589 590 allow = (* unix_user_function) (connection, 591 auth_identity.uid, 592 unix_user_data); 593 594 _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME); 595 _dbus_connection_lock (connection); 596 597 if (allow) 598 { 599 _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid); 600 } 601 else 602 { 603 _dbus_verbose ("Client UID "DBUS_UID_FORMAT 604 " was rejected, disconnecting\n", 605 auth_identity.uid); 606 _dbus_transport_disconnect (transport); 607 _dbus_connection_unref_unlocked (connection); 608 return FALSE; 609 } 610 } 611 else 612 { 613 DBusCredentials our_identity; 614 615 _dbus_credentials_from_current_process (&our_identity); 616 617 if (!_dbus_credentials_match (&our_identity, 618 &auth_identity)) 619 { 620 _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT 621 " but our UID is "DBUS_UID_FORMAT", disconnecting\n", 622 auth_identity.uid, our_identity.uid); 623 _dbus_transport_disconnect (transport); 624 _dbus_connection_unref_unlocked (transport->connection); 625 return FALSE; 626 } 627 else 628 { 629 _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT 630 " matching our UID "DBUS_UID_FORMAT"\n", 631 auth_identity.uid, our_identity.uid); 632 } 633 } 634 } 635 636 transport->authenticated = maybe_authenticated; 637 638 _dbus_connection_unref_unlocked (transport->connection); 639 return maybe_authenticated; 640 } 641 } 642 643 /** 644 * Gets the address of a transport. It will be 645 * #NULL for a server-side transport. 646 * 647 * @param transport the transport 648 * @returns transport's address 649 */ 650 const char* 651 _dbus_transport_get_address (DBusTransport *transport) 652 { 653 return transport->address; 654 } 655 656 /** 657 * Handles a watch by reading data, writing data, or disconnecting 658 * the transport, as appropriate for the given condition. 659 * 660 * @param transport the transport. 661 * @param watch the watch. 662 * @param condition the current state of the watched file descriptor. 663 * @returns #FALSE if not enough memory to fully handle the watch 664 */ 665 dbus_bool_t 666 _dbus_transport_handle_watch (DBusTransport *transport, 667 DBusWatch *watch, 668 unsigned int condition) 669 { 670 dbus_bool_t retval; 671 672 _dbus_assert (transport->vtable->handle_watch != NULL); 673 674 if (transport->disconnected) 675 return TRUE; 676 677 if (dbus_watch_get_fd (watch) < 0) 678 { 679 _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n"); 680 return TRUE; 681 } 682 683 _dbus_watch_sanitize_condition (watch, &condition); 684 685 _dbus_transport_ref (transport); 686 _dbus_watch_ref (watch); 687 retval = (* transport->vtable->handle_watch) (transport, watch, condition); 688 _dbus_watch_unref (watch); 689 _dbus_transport_unref (transport); 690 691 return retval; 692 } 693 694 /** 695 * Sets the connection using this transport. Allows the transport 696 * to add watches to the connection, queue incoming messages, 697 * and pull outgoing messages. 698 * 699 * @param transport the transport. 700 * @param connection the connection. 701 * @returns #FALSE if not enough memory 702 */ 703 dbus_bool_t 704 _dbus_transport_set_connection (DBusTransport *transport, 705 DBusConnection *connection) 706 { 707 _dbus_assert (transport->vtable->connection_set != NULL); 708 _dbus_assert (transport->connection == NULL); 709 710 transport->connection = connection; 711 712 _dbus_transport_ref (transport); 713 if (!(* transport->vtable->connection_set) (transport)) 714 transport->connection = NULL; 715 _dbus_transport_unref (transport); 716 717 return transport->connection != NULL; 718 } 719 720 /** 721 * Get the socket file descriptor, if any. 722 * 723 * @param transport the transport 724 * @param fd_p pointer to fill in with the descriptor 725 * @returns #TRUE if a descriptor was available 726 */ 727 dbus_bool_t 728 _dbus_transport_get_socket_fd (DBusTransport *transport, 729 int *fd_p) 730 { 731 dbus_bool_t retval; 732 733 if (transport->vtable->get_socket_fd == NULL) 734 return FALSE; 735 736 if (transport->disconnected) 737 return FALSE; 738 739 _dbus_transport_ref (transport); 740 741 retval = (* transport->vtable->get_socket_fd) (transport, 742 fd_p); 743 744 _dbus_transport_unref (transport); 745 746 return retval; 747 } 748 749 /** 750 * Performs a single poll()/select() on the transport's file 751 * descriptors and then reads/writes data as appropriate, 752 * queueing incoming messages and sending outgoing messages. 753 * This is the backend for _dbus_connection_do_iteration(). 754 * See _dbus_connection_do_iteration() for full details. 755 * 756 * @param transport the transport. 757 * @param flags indicates whether to read or write, and whether to block. 758 * @param timeout_milliseconds if blocking, timeout or -1 for no timeout. 759 */ 760 void 761 _dbus_transport_do_iteration (DBusTransport *transport, 762 unsigned int flags, 763 int timeout_milliseconds) 764 { 765 _dbus_assert (transport->vtable->do_iteration != NULL); 766 767 _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n", 768 flags, timeout_milliseconds, !transport->disconnected); 769 770 if ((flags & (DBUS_ITERATION_DO_WRITING | 771 DBUS_ITERATION_DO_READING)) == 0) 772 return; /* Nothing to do */ 773 774 if (transport->disconnected) 775 return; 776 777 _dbus_transport_ref (transport); 778 (* transport->vtable->do_iteration) (transport, flags, 779 timeout_milliseconds); 780 _dbus_transport_unref (transport); 781 782 _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); 783 } 784 785 static dbus_bool_t 786 recover_unused_bytes (DBusTransport *transport) 787 { 788 if (_dbus_auth_needs_decoding (transport->auth)) 789 { 790 DBusString plaintext; 791 const DBusString *encoded; 792 DBusString *buffer; 793 int orig_len; 794 795 if (!_dbus_string_init (&plaintext)) 796 goto nomem; 797 798 _dbus_auth_get_unused_bytes (transport->auth, 799 &encoded); 800 801 if (!_dbus_auth_decode_data (transport->auth, 802 encoded, &plaintext)) 803 { 804 _dbus_string_free (&plaintext); 805 goto nomem; 806 } 807 808 _dbus_message_loader_get_buffer (transport->loader, 809 &buffer); 810 811 orig_len = _dbus_string_get_length (buffer); 812 813 if (!_dbus_string_move (&plaintext, 0, buffer, 814 orig_len)) 815 { 816 _dbus_string_free (&plaintext); 817 goto nomem; 818 } 819 820 _dbus_verbose (" %d unused bytes sent to message loader\n", 821 _dbus_string_get_length (buffer) - 822 orig_len); 823 824 _dbus_message_loader_return_buffer (transport->loader, 825 buffer, 826 _dbus_string_get_length (buffer) - 827 orig_len); 828 829 _dbus_auth_delete_unused_bytes (transport->auth); 830 831 _dbus_string_free (&plaintext); 832 } 833 else 834 { 835 const DBusString *bytes; 836 DBusString *buffer; 837 int orig_len; 838 dbus_bool_t succeeded; 839 840 _dbus_message_loader_get_buffer (transport->loader, 841 &buffer); 842 843 orig_len = _dbus_string_get_length (buffer); 844 845 _dbus_auth_get_unused_bytes (transport->auth, 846 &bytes); 847 848 succeeded = TRUE; 849 if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer))) 850 succeeded = FALSE; 851 852 _dbus_verbose (" %d unused bytes sent to message loader\n", 853 _dbus_string_get_length (buffer) - 854 orig_len); 855 856 _dbus_message_loader_return_buffer (transport->loader, 857 buffer, 858 _dbus_string_get_length (buffer) - 859 orig_len); 860 861 if (succeeded) 862 _dbus_auth_delete_unused_bytes (transport->auth); 863 else 864 goto nomem; 865 } 866 867 return TRUE; 868 869 nomem: 870 _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n"); 871 return FALSE; 872 } 873 874 /** 875 * Reports our current dispatch status (whether there's buffered 876 * data to be queued as messages, or not, or we need memory). 877 * 878 * @param transport the transport 879 * @returns current status 880 */ 881 DBusDispatchStatus 882 _dbus_transport_get_dispatch_status (DBusTransport *transport) 883 { 884 if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size) 885 return DBUS_DISPATCH_COMPLETE; /* complete for now */ 886 887 if (!_dbus_transport_get_is_authenticated (transport)) 888 { 889 if (_dbus_auth_do_work (transport->auth) == 890 DBUS_AUTH_STATE_WAITING_FOR_MEMORY) 891 return DBUS_DISPATCH_NEED_MEMORY; 892 else if (!_dbus_transport_get_is_authenticated (transport)) 893 return DBUS_DISPATCH_COMPLETE; 894 } 895 896 if (!transport->unused_bytes_recovered && 897 !recover_unused_bytes (transport)) 898 return DBUS_DISPATCH_NEED_MEMORY; 899 900 transport->unused_bytes_recovered = TRUE; 901 902 if (!_dbus_message_loader_queue_messages (transport->loader)) 903 return DBUS_DISPATCH_NEED_MEMORY; 904 905 if (_dbus_message_loader_peek_message (transport->loader) != NULL) 906 return DBUS_DISPATCH_DATA_REMAINS; 907 else 908 return DBUS_DISPATCH_COMPLETE; 909 } 910 911 /** 912 * Processes data we've read while handling a watch, potentially 913 * converting some of it to messages and queueing those messages on 914 * the connection. 915 * 916 * @param transport the transport 917 * @returns #TRUE if we had enough memory to queue all messages 918 */ 919 dbus_bool_t 920 _dbus_transport_queue_messages (DBusTransport *transport) 921 { 922 DBusDispatchStatus status; 923 924 #if 0 925 _dbus_verbose ("_dbus_transport_queue_messages()\n"); 926 #endif 927 928 /* Queue any messages */ 929 while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS) 930 { 931 DBusMessage *message; 932 DBusList *link; 933 934 link = _dbus_message_loader_pop_message_link (transport->loader); 935 _dbus_assert (link != NULL); 936 937 message = link->data; 938 939 _dbus_verbose ("queueing received message %p\n", message); 940 941 if (!_dbus_message_add_size_counter (message, transport->live_messages_size)) 942 { 943 _dbus_message_loader_putback_message_link (transport->loader, 944 link); 945 status = DBUS_DISPATCH_NEED_MEMORY; 946 break; 947 } 948 else 949 { 950 /* pass ownership of link and message ref to connection */ 951 _dbus_connection_queue_received_message_link (transport->connection, 952 link); 953 } 954 } 955 956 if (_dbus_message_loader_get_is_corrupted (transport->loader)) 957 { 958 _dbus_verbose ("Corrupted message stream, disconnecting\n"); 959 _dbus_transport_disconnect (transport); 960 } 961 962 return status != DBUS_DISPATCH_NEED_MEMORY; 963 } 964 965 /** 966 * See dbus_connection_set_max_message_size(). 967 * 968 * @param transport the transport 969 * @param size the max size of a single message 970 */ 971 void 972 _dbus_transport_set_max_message_size (DBusTransport *transport, 973 long size) 974 { 975 _dbus_message_loader_set_max_message_size (transport->loader, size); 976 } 977 978 /** 979 * See dbus_connection_get_max_message_size(). 980 * 981 * @param transport the transport 982 * @returns max message size 983 */ 984 long 985 _dbus_transport_get_max_message_size (DBusTransport *transport) 986 { 987 return _dbus_message_loader_get_max_message_size (transport->loader); 988 } 989 990 /** 991 * See dbus_connection_set_max_received_size(). 992 * 993 * @param transport the transport 994 * @param size the max size of all incoming messages 995 */ 996 void 997 _dbus_transport_set_max_received_size (DBusTransport *transport, 998 long size) 999 { 1000 transport->max_live_messages_size = size; 1001 _dbus_counter_set_notify (transport->live_messages_size, 1002 transport->max_live_messages_size, 1003 live_messages_size_notify, 1004 transport); 1005 } 1006 1007 1008 /** 1009 * See dbus_connection_get_max_received_size(). 1010 * 1011 * @param transport the transport 1012 * @returns max bytes for all live messages 1013 */ 1014 long 1015 _dbus_transport_get_max_received_size (DBusTransport *transport) 1016 { 1017 return transport->max_live_messages_size; 1018 } 1019 1020 /** 1021 * See dbus_connection_get_unix_user(). 1022 * 1023 * @param transport the transport 1024 * @param uid return location for the user ID 1025 * @returns #TRUE if uid is filled in with a valid user ID 1026 */ 1027 dbus_bool_t 1028 _dbus_transport_get_unix_user (DBusTransport *transport, 1029 unsigned long *uid) 1030 { 1031 DBusCredentials auth_identity; 1032 1033 *uid = _DBUS_INT32_MAX; /* better than some root or system user in 1034 * case of bugs in the caller. Caller should 1035 * never use this value on purpose, however. 1036 */ 1037 1038 if (!transport->authenticated) 1039 return FALSE; 1040 1041 _dbus_auth_get_identity (transport->auth, &auth_identity); 1042 1043 if (auth_identity.uid != DBUS_UID_UNSET) 1044 { 1045 *uid = auth_identity.uid; 1046 return TRUE; 1047 } 1048 else 1049 return FALSE; 1050 } 1051 1052 /** 1053 * See dbus_connection_get_unix_process_id(). 1054 * 1055 * @param transport the transport 1056 * @param pid return location for the process ID 1057 * @returns #TRUE if uid is filled in with a valid process ID 1058 */ 1059 dbus_bool_t 1060 _dbus_transport_get_unix_process_id (DBusTransport *transport, 1061 unsigned long *pid) 1062 { 1063 DBusCredentials auth_identity; 1064 1065 *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose, 1066 * but we set it to a safe number, INT_MAX, 1067 * just to root out possible bugs in bad callers. 1068 */ 1069 1070 if (!transport->authenticated) 1071 return FALSE; 1072 1073 _dbus_auth_get_identity (transport->auth, &auth_identity); 1074 1075 if (auth_identity.pid != DBUS_PID_UNSET) 1076 { 1077 *pid = auth_identity.pid; 1078 return TRUE; 1079 } 1080 else 1081 return FALSE; 1082 } 1083 1084 /** 1085 * See dbus_connection_set_unix_user_function(). 1086 * 1087 * @param transport the transport 1088 * @param function the predicate 1089 * @param data data to pass to the predicate 1090 * @param free_data_function function to free the data 1091 * @param old_data the old user data to be freed 1092 * @param old_free_data_function old free data function to free it with 1093 */ 1094 void 1095 _dbus_transport_set_unix_user_function (DBusTransport *transport, 1096 DBusAllowUnixUserFunction function, 1097 void *data, 1098 DBusFreeFunction free_data_function, 1099 void **old_data, 1100 DBusFreeFunction *old_free_data_function) 1101 { 1102 *old_data = transport->unix_user_data; 1103 *old_free_data_function = transport->free_unix_user_data; 1104 1105 transport->unix_user_function = function; 1106 transport->unix_user_data = data; 1107 transport->free_unix_user_data = free_data_function; 1108 } 1109 1110 /** 1111 * Sets the SASL authentication mechanisms supported by this transport. 1112 * 1113 * @param transport the transport 1114 * @param mechanisms the #NULL-terminated array of mechanisms 1115 * 1116 * @returns #FALSE if no memory 1117 */ 1118 dbus_bool_t 1119 _dbus_transport_set_auth_mechanisms (DBusTransport *transport, 1120 const char **mechanisms) 1121 { 1122 return _dbus_auth_set_mechanisms (transport->auth, mechanisms); 1123 } 1124 1125 1126 /** @} */ 1127