1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-transport.c DBusTransport object (internal to D-BUS implementation)
4 * Copyright (C) 2002, 2003 Red Hat Inc.
6 * Licensed under the Academic Free License version 1.2
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.
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.
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
24 #include "dbus-transport-protected.h"
25 #include "dbus-transport-unix.h"
26 #include "dbus-connection-internal.h"
27 #include "dbus-watch.h"
28 #include "dbus-auth.h"
29 #include "dbus-address.h"
30 #ifdef DBUS_BUILD_TESTS
31 #include "dbus-transport-debug.h"
32 #include "dbus-server-debug-pipe.h"
36 * @defgroup DBusTransport DBusTransport object
37 * @ingroup DBusInternals
38 * @brief "Backend" for a DBusConnection.
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.
48 * @typedef DBusTransport
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.
57 live_messages_size_notify (DBusCounter *counter,
60 DBusTransport *transport = user_data;
62 _dbus_transport_ref (transport);
65 _dbus_verbose ("Counter value is now %d\n",
66 (int) _dbus_counter_get_value (counter));
69 /* disable or re-enable the read watch for the transport if
72 if (* transport->vtable->live_messages_changed)
73 (* transport->vtable->live_messages_changed) (transport);
75 _dbus_transport_unref (transport);
79 * Initializes the base class members of DBusTransport.
80 * Chained up to by subclasses in their constructor.
82 * @param transport the transport being created.
83 * @param vtable the subclass vtable.
84 * @param server #TRUE if this transport is on the server side of a connection
85 * @param address the address of the transport
86 * @returns #TRUE on success.
89 _dbus_transport_init_base (DBusTransport *transport,
90 const DBusTransportVTable *vtable,
92 const DBusString *address)
94 DBusMessageLoader *loader;
99 loader = _dbus_message_loader_new ();
104 auth = _dbus_auth_server_new ();
106 auth = _dbus_auth_client_new ();
109 _dbus_message_loader_unref (loader);
113 counter = _dbus_counter_new ();
116 _dbus_auth_unref (auth);
117 _dbus_message_loader_unref (loader);
123 _dbus_assert (address == NULL);
128 _dbus_assert (address != NULL);
130 if (!_dbus_string_copy_data (address, &address_copy))
132 _dbus_counter_unref (counter);
133 _dbus_auth_unref (auth);
134 _dbus_message_loader_unref (loader);
139 transport->refcount = 1;
140 transport->vtable = vtable;
141 transport->loader = loader;
142 transport->auth = auth;
143 transport->live_messages_size = counter;
144 transport->authenticated = FALSE;
145 transport->messages_need_sending = FALSE;
146 transport->disconnected = FALSE;
147 transport->send_credentials_pending = !server;
148 transport->receive_credentials_pending = server;
149 transport->is_server = server;
150 transport->address = address_copy;
152 transport->unix_user_function = NULL;
153 transport->unix_user_data = NULL;
154 transport->free_unix_user_data = NULL;
156 /* Try to default to something that won't totally hose the system,
157 * but doesn't impose too much of a limitation.
159 transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
161 transport->credentials.pid = -1;
162 transport->credentials.uid = -1;
163 transport->credentials.gid = -1;
165 _dbus_counter_set_notify (transport->live_messages_size,
166 transport->max_live_messages_size,
167 live_messages_size_notify,
170 if (transport->address)
171 _dbus_verbose ("Initialized transport on address %s\n", transport->address);
177 * Finalizes base class members of DBusTransport.
178 * Chained up to from subclass finalizers.
180 * @param transport the transport.
183 _dbus_transport_finalize_base (DBusTransport *transport)
185 if (!transport->disconnected)
186 _dbus_transport_disconnect (transport);
188 if (transport->free_unix_user_data != NULL)
189 (* transport->free_unix_user_data) (transport->unix_user_data);
191 _dbus_message_loader_unref (transport->loader);
192 _dbus_auth_unref (transport->auth);
193 _dbus_counter_set_notify (transport->live_messages_size,
195 _dbus_counter_unref (transport->live_messages_size);
196 dbus_free (transport->address);
200 * Opens a new transport for the given address. (This opens a
201 * client-side-of-the-connection transport.)
203 * @todo error messages on bad address could really be better.
204 * DBusResultCode is a bit limiting here.
206 * @param address the address.
207 * @param error location to store reason for failure.
208 * @returns new transport of #NULL on failure.
211 _dbus_transport_open (const char *address,
214 DBusTransport *transport;
215 DBusAddressEntry **entries;
217 DBusError first_error;
219 const char *address_problem_type;
220 const char *address_problem_field;
221 const char *address_problem_other;
223 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
225 if (!dbus_parse_address (address, &entries, &len, error))
228 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
231 address_problem_type = NULL;
232 address_problem_field = NULL;
233 address_problem_other = NULL;
235 dbus_error_init (&tmp_error);
236 dbus_error_init (&first_error);
237 for (i = 0; i < len; i++)
241 method = dbus_address_entry_get_method (entries[i]);
243 if (strcmp (method, "unix") == 0)
245 const char *path = dbus_address_entry_get_value (entries[i], "path");
246 const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir");
250 address_problem_other = "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on";
256 address_problem_type = "unix";
257 address_problem_field = "path";
261 transport = _dbus_transport_new_for_domain_socket (path, &tmp_error);
263 else if (strcmp (method, "tcp") == 0)
265 const char *host = dbus_address_entry_get_value (entries[i], "host");
266 const char *port = dbus_address_entry_get_value (entries[i], "port");
273 address_problem_type = "tcp";
274 address_problem_field = "port";
278 _dbus_string_init_const (&str, port);
279 sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
280 _dbus_string_free (&str);
282 if (sresult == FALSE || lport <= 0 || lport > 65535)
284 address_problem_other = "Port is not an integer between 0 and 65535";
288 transport = _dbus_transport_new_for_tcp_socket (host, lport, &tmp_error);
290 #ifdef DBUS_BUILD_TESTS
291 else if (strcmp (method, "debug") == 0)
293 const char *name = dbus_address_entry_get_value (entries[i], "name");
297 address_problem_type = "debug";
298 address_problem_field = "name";
302 transport = _dbus_transport_debug_client_new (name, &tmp_error);
304 else if (strcmp (method, "debug-pipe") == 0)
306 const char *name = dbus_address_entry_get_value (entries[i], "name");
310 address_problem_type = "debug-pipe";
311 address_problem_field = "name";
315 transport = _dbus_transport_debug_pipe_new (name, &tmp_error);
320 address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
327 _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
330 dbus_move_error (&tmp_error, &first_error);
332 dbus_error_free (&tmp_error);
335 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
336 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
338 if (transport == NULL)
340 _DBUS_ASSERT_ERROR_IS_SET (&first_error);
341 dbus_move_error (&first_error, error);
345 dbus_error_free (&first_error);
348 dbus_address_entries_free (entries);
352 dbus_address_entries_free (entries);
354 if (address_problem_type != NULL)
355 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
356 "Address of type %s was missing argument %s",
357 address_problem_type, address_problem_field);
359 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
360 "Could not parse address: %s",
361 address_problem_other);
367 * Increments the reference count for the transport.
369 * @param transport the transport.
372 _dbus_transport_ref (DBusTransport *transport)
374 _dbus_assert (transport->refcount > 0);
376 transport->refcount += 1;
380 * Decrements the reference count for the transport.
381 * Disconnects and finalizes the transport if
382 * the reference count reaches zero.
384 * @param transport the transport.
387 _dbus_transport_unref (DBusTransport *transport)
389 _dbus_assert (transport != NULL);
390 _dbus_assert (transport->refcount > 0);
392 transport->refcount -= 1;
393 if (transport->refcount == 0)
395 _dbus_assert (transport->vtable->finalize != NULL);
397 (* transport->vtable->finalize) (transport);
402 * Closes our end of the connection to a remote application. Further
403 * attempts to use this transport will fail. Only the first call to
404 * _dbus_transport_disconnect() will have an effect.
406 * @param transport the transport.
410 _dbus_transport_disconnect (DBusTransport *transport)
412 _dbus_assert (transport->vtable->disconnect != NULL);
414 if (transport->disconnected)
417 (* transport->vtable->disconnect) (transport);
419 transport->disconnected = TRUE;
421 if (transport->connection)
422 _dbus_connection_notify_disconnected (transport->connection);
426 * Returns #TRUE if the transport has not been disconnected.
427 * Disconnection can result from _dbus_transport_disconnect()
428 * or because the server drops its end of the connection.
430 * @param transport the transport.
431 * @returns whether we're connected
434 _dbus_transport_get_is_connected (DBusTransport *transport)
436 return !transport->disconnected;
440 * Returns #TRUE if we have been authenticated. Will return #TRUE
441 * even if the transport is disconnected.
443 * @todo needs to drop connection->mutex when calling the unix_user_function
445 * @param transport the transport
446 * @returns whether we're authenticated
449 _dbus_transport_get_is_authenticated (DBusTransport *transport)
451 if (transport->authenticated)
455 dbus_bool_t maybe_authenticated;
457 if (transport->disconnected)
460 maybe_authenticated =
461 (!(transport->send_credentials_pending ||
462 transport->receive_credentials_pending));
464 if (maybe_authenticated)
466 switch (_dbus_auth_do_work (transport->auth))
468 case DBUS_AUTH_STATE_AUTHENTICATED:
469 case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
470 /* leave as maybe_authenticated */
473 maybe_authenticated = FALSE;
477 /* If we've authenticated as some identity, check that the auth
478 * identity is the same as our own identity. In the future, we
479 * may have API allowing applications to specify how this is
480 * done, for example they may allow connection as any identity,
481 * but then impose restrictions on certain identities.
482 * Or they may give certain identities extra privileges.
485 if (maybe_authenticated && transport->is_server)
487 DBusCredentials auth_identity;
489 _dbus_auth_get_identity (transport->auth, &auth_identity);
491 if (transport->unix_user_function != NULL)
493 /* FIXME we hold the connection lock here and should drop it */
494 if (!(* transport->unix_user_function) (transport->connection,
496 transport->unix_user_data))
498 _dbus_verbose ("Client UID "DBUS_UID_FORMAT
499 " was rejected, disconnecting\n",
501 _dbus_transport_disconnect (transport);
506 _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid);
511 DBusCredentials our_identity;
513 _dbus_credentials_from_current_process (&our_identity);
515 if (!_dbus_credentials_match (&our_identity,
518 _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
519 " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
520 auth_identity.uid, our_identity.uid);
521 _dbus_transport_disconnect (transport);
526 _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
527 " matching our UID "DBUS_UID_FORMAT"\n",
528 auth_identity.uid, our_identity.uid);
533 transport->authenticated = maybe_authenticated;
535 return transport->authenticated;
540 * Gets the address of a transport. It will be
541 * #NULL for a server-side transport.
543 * @param transport the transport
544 * @returns transport's address
547 _dbus_transport_get_address (DBusTransport *transport)
549 return transport->address;
553 * Handles a watch by reading data, writing data, or disconnecting
554 * the transport, as appropriate for the given condition.
556 * @param transport the transport.
557 * @param watch the watch.
558 * @param condition the current state of the watched file descriptor.
559 * @returns #FALSE if not enough memory to fully handle the watch
562 _dbus_transport_handle_watch (DBusTransport *transport,
564 unsigned int condition)
568 _dbus_assert (transport->vtable->handle_watch != NULL);
570 if (transport->disconnected)
573 if (dbus_watch_get_fd (watch) < 0)
575 _dbus_warn ("Tried to handle an invalidated watch; this watch should have been removed\n");
579 _dbus_watch_sanitize_condition (watch, &condition);
581 _dbus_transport_ref (transport);
582 _dbus_watch_ref (watch);
583 retval = (* transport->vtable->handle_watch) (transport, watch, condition);
584 _dbus_watch_unref (watch);
585 _dbus_transport_unref (transport);
591 * Sets the connection using this transport. Allows the transport
592 * to add watches to the connection, queue incoming messages,
593 * and pull outgoing messages.
595 * @param transport the transport.
596 * @param connection the connection.
597 * @returns #FALSE if not enough memory
600 _dbus_transport_set_connection (DBusTransport *transport,
601 DBusConnection *connection)
603 _dbus_assert (transport->vtable->connection_set != NULL);
604 _dbus_assert (transport->connection == NULL);
606 transport->connection = connection;
608 _dbus_transport_ref (transport);
609 if (!(* transport->vtable->connection_set) (transport))
610 transport->connection = NULL;
611 _dbus_transport_unref (transport);
613 return transport->connection != NULL;
617 * Notifies the transport when the outgoing message queue goes from
618 * empty to non-empty or vice versa. Typically causes the transport to
619 * add or remove its DBUS_WATCH_WRITABLE watch.
621 * @param transport the transport.
622 * @param queue_length the length of the outgoing message queue.
626 _dbus_transport_messages_pending (DBusTransport *transport,
629 _dbus_assert (transport->vtable->messages_pending != NULL);
631 if (transport->disconnected)
634 transport->messages_need_sending = queue_length > 0;
636 _dbus_transport_ref (transport);
637 (* transport->vtable->messages_pending) (transport,
639 _dbus_transport_unref (transport);
643 * Performs a single poll()/select() on the transport's file
644 * descriptors and then reads/writes data as appropriate,
645 * queueing incoming messages and sending outgoing messages.
646 * This is the backend for _dbus_connection_do_iteration().
647 * See _dbus_connection_do_iteration() for full details.
649 * @param transport the transport.
650 * @param flags indicates whether to read or write, and whether to block.
651 * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
654 _dbus_transport_do_iteration (DBusTransport *transport,
656 int timeout_milliseconds)
658 _dbus_assert (transport->vtable->do_iteration != NULL);
660 _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
661 flags, timeout_milliseconds, !transport->disconnected);
663 if ((flags & (DBUS_ITERATION_DO_WRITING |
664 DBUS_ITERATION_DO_READING)) == 0)
665 return; /* Nothing to do */
667 if (transport->disconnected)
670 _dbus_transport_ref (transport);
671 (* transport->vtable->do_iteration) (transport, flags,
672 timeout_milliseconds);
673 _dbus_transport_unref (transport);
677 recover_unused_bytes (DBusTransport *transport)
679 if (_dbus_auth_do_work (transport->auth) != DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES)
682 if (_dbus_auth_needs_decoding (transport->auth))
684 DBusString plaintext;
685 const DBusString *encoded;
689 if (!_dbus_string_init (&plaintext))
692 _dbus_auth_get_unused_bytes (transport->auth,
695 if (!_dbus_auth_decode_data (transport->auth,
696 encoded, &plaintext))
698 _dbus_string_free (&plaintext);
702 _dbus_message_loader_get_buffer (transport->loader,
705 orig_len = _dbus_string_get_length (buffer);
707 if (!_dbus_string_move (&plaintext, 0, buffer,
710 _dbus_string_free (&plaintext);
714 _dbus_verbose (" %d unused bytes sent to message loader\n",
715 _dbus_string_get_length (buffer) -
718 _dbus_message_loader_return_buffer (transport->loader,
720 _dbus_string_get_length (buffer) -
723 _dbus_auth_delete_unused_bytes (transport->auth);
725 _dbus_string_free (&plaintext);
729 const DBusString *bytes;
732 dbus_bool_t succeeded;
734 _dbus_message_loader_get_buffer (transport->loader,
737 orig_len = _dbus_string_get_length (buffer);
739 _dbus_auth_get_unused_bytes (transport->auth,
743 if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
746 _dbus_verbose (" %d unused bytes sent to message loader\n",
747 _dbus_string_get_length (buffer) -
750 _dbus_message_loader_return_buffer (transport->loader,
752 _dbus_string_get_length (buffer) -
756 _dbus_auth_delete_unused_bytes (transport->auth);
764 _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
769 * Reports our current dispatch status (whether there's buffered
770 * data to be queued as messages, or not, or we need memory).
772 * @param transport the transport
773 * @returns current status
776 _dbus_transport_get_dispatch_status (DBusTransport *transport)
778 if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size)
779 return DBUS_DISPATCH_COMPLETE; /* complete for now */
781 if (!_dbus_transport_get_is_authenticated (transport))
783 if (_dbus_auth_do_work (transport->auth) ==
784 DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
785 return DBUS_DISPATCH_NEED_MEMORY;
787 return DBUS_DISPATCH_COMPLETE;
790 if (!transport->unused_bytes_recovered &&
791 !recover_unused_bytes (transport))
792 return DBUS_DISPATCH_NEED_MEMORY;
794 transport->unused_bytes_recovered = TRUE;
796 if (!_dbus_message_loader_queue_messages (transport->loader))
797 return DBUS_DISPATCH_NEED_MEMORY;
799 if (_dbus_message_loader_peek_message (transport->loader) != NULL)
800 return DBUS_DISPATCH_DATA_REMAINS;
802 return DBUS_DISPATCH_COMPLETE;
806 * Processes data we've read while handling a watch, potentially
807 * converting some of it to messages and queueing those messages on
810 * @param transport the transport
811 * @returns #TRUE if we had enough memory to queue all messages
814 _dbus_transport_queue_messages (DBusTransport *transport)
816 DBusDispatchStatus status;
818 _dbus_verbose ("_dbus_transport_queue_messages()\n");
820 /* Queue any messages */
821 while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
823 DBusMessage *message;
826 link = _dbus_message_loader_pop_message_link (transport->loader);
827 _dbus_assert (link != NULL);
829 message = link->data;
831 _dbus_verbose ("queueing received message %p\n", message);
833 _dbus_message_add_size_counter (message, transport->live_messages_size);
835 /* pass ownership of link and message ref to connection */
836 _dbus_connection_queue_received_message_link (transport->connection,
840 if (_dbus_message_loader_get_is_corrupted (transport->loader))
842 _dbus_verbose ("Corrupted message stream, disconnecting\n");
843 _dbus_transport_disconnect (transport);
846 return status != DBUS_DISPATCH_NEED_MEMORY;
850 * See dbus_connection_set_max_message_size().
852 * @param transport the transport
853 * @param size the max size of a single message
856 _dbus_transport_set_max_message_size (DBusTransport *transport,
859 _dbus_message_loader_set_max_message_size (transport->loader, size);
863 * See dbus_connection_get_max_message_size().
865 * @param transport the transport
866 * @returns max message size
869 _dbus_transport_get_max_message_size (DBusTransport *transport)
871 return _dbus_message_loader_get_max_message_size (transport->loader);
875 * See dbus_connection_set_max_live_messages_size().
877 * @param transport the transport
878 * @param size the max size of all incoming messages
881 _dbus_transport_set_max_live_messages_size (DBusTransport *transport,
884 transport->max_live_messages_size = size;
885 _dbus_counter_set_notify (transport->live_messages_size,
886 transport->max_live_messages_size,
887 live_messages_size_notify,
893 * See dbus_connection_get_max_live_messages_size().
895 * @param transport the transport
896 * @returns max bytes for all live messages
899 _dbus_transport_get_max_live_messages_size (DBusTransport *transport)
901 return transport->max_live_messages_size;
905 * See dbus_connection_get_unix_user().
907 * @param transport the transport
908 * @param uid return location for the user ID
909 * @returns #TRUE if uid is filled in with a valid user ID
912 _dbus_transport_get_unix_user (DBusTransport *transport,
915 DBusCredentials auth_identity;
917 *uid = _DBUS_INT_MAX; /* better than some root or system user in
918 * case of bugs in the caller. Caller should
919 * never use this value on purpose, however.
922 if (!transport->authenticated)
925 _dbus_auth_get_identity (transport->auth, &auth_identity);
927 if (auth_identity.uid >= 0)
929 *uid = auth_identity.uid;
937 * See dbus_connection_set_unix_user_function().
939 * @param transport the transport
940 * @param function the predicate
941 * @param data data to pass to the predicate
942 * @param free_data_function function to free the data
943 * @param old_data the old user data to be freed
944 * @param old_free_data_function old free data function to free it with
947 _dbus_transport_set_unix_user_function (DBusTransport *transport,
948 DBusAllowUnixUserFunction function,
950 DBusFreeFunction free_data_function,
952 DBusFreeFunction *old_free_data_function)
954 *old_data = transport->unix_user_data;
955 *old_free_data_function = transport->free_unix_user_data;
957 transport->unix_user_function = function;
958 transport->unix_user_data = data;
959 transport->free_unix_user_data = free_data_function;
963 * Sets the SASL authentication mechanisms supported by this transport.
965 * @param transport the transport
966 * @param mechanisms the #NULL-terminated array of mechanisms
968 * @returns #FALSE if no memory
971 _dbus_transport_set_auth_mechanisms (DBusTransport *transport,
972 const char **mechanisms)
974 return _dbus_auth_set_mechanisms (transport->auth, mechanisms);