*
*/
+#include <config.h>
#include "dbus-transport-protected.h"
#include "dbus-transport-unix.h"
#include "dbus-transport-socket.h"
#include "dbus-connection-internal.h"
#include "dbus-watch.h"
#include "dbus-auth.h"
+#include "dbus-authorization.h"
#include "dbus-address.h"
#include "dbus-credentials.h"
-#ifdef DBUS_BUILD_TESTS
+#include "dbus-mainloop.h"
+#include "dbus-message.h"
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
#include "dbus-server-debug-pipe.h"
#endif
*/
static void
-live_messages_size_notify (DBusCounter *counter,
+live_messages_notify (DBusCounter *counter,
void *user_data)
{
DBusTransport *transport = user_data;
_dbus_transport_ref (transport);
#if 0
- _dbus_verbose ("Counter value is now %d\n",
- (int) _dbus_counter_get_value (counter));
+ _dbus_verbose ("Size counter value is now %d\n",
+ (int) _dbus_counter_get_size_value (counter));
+ _dbus_verbose ("Unix FD counter value is now %d\n",
+ (int) _dbus_counter_get_unix_fd_value (counter));
#endif
-
+
/* disable or re-enable the read watch for the transport if
* required.
*/
if (transport->vtable->live_messages_changed)
- (* transport->vtable->live_messages_changed) (transport);
+ {
+ _dbus_connection_lock (transport->connection);
+ (* transport->vtable->live_messages_changed) (transport);
+ _dbus_connection_unlock (transport->connection);
+ }
_dbus_transport_unref (transport);
}
{
DBusMessageLoader *loader;
DBusAuth *auth;
+ DBusAuthorization *authorization = NULL; /* non-NULL only if is_server=TRUE */
DBusCounter *counter;
char *address_copy;
DBusCredentials *creds;
loader = _dbus_message_loader_new ();
if (loader == NULL)
return FALSE;
-
- if (server_guid)
- auth = _dbus_auth_server_new (server_guid);
+
+ if (server_guid != NULL)
+ {
+ authorization = _dbus_authorization_new ();
+ if (authorization == NULL)
+ {
+ _dbus_message_loader_unref (loader);
+ return FALSE; /* OOM */
+ }
+
+ auth = _dbus_auth_server_new (server_guid);
+ }
else
- auth = _dbus_auth_client_new ();
+ {
+ auth = _dbus_auth_client_new ();
+ }
if (auth == NULL)
{
+ if (authorization != NULL)
+ _dbus_authorization_unref (authorization);
_dbus_message_loader_unref (loader);
return FALSE;
}
if (counter == NULL)
{
_dbus_auth_unref (auth);
+ if (authorization != NULL)
+ _dbus_authorization_unref (authorization);
_dbus_message_loader_unref (loader);
return FALSE;
}
{
_dbus_counter_unref (counter);
_dbus_auth_unref (auth);
+ if (authorization != NULL)
+ _dbus_authorization_unref (authorization);
_dbus_message_loader_unref (loader);
return FALSE;
}
- if (server_guid)
+ if (server_guid != NULL)
{
_dbus_assert (address == NULL);
address_copy = NULL;
_dbus_credentials_unref (creds);
_dbus_counter_unref (counter);
_dbus_auth_unref (auth);
+ if (authorization != NULL)
+ _dbus_authorization_unref (authorization);
_dbus_message_loader_unref (loader);
return FALSE;
}
transport->refcount = 1;
transport->vtable = vtable;
transport->loader = loader;
+ transport->authorization = authorization;
transport->auth = auth;
- transport->live_messages_size = counter;
+ transport->live_messages = counter;
transport->authenticated = FALSE;
transport->disconnected = FALSE;
transport->is_server = (server_guid != NULL);
transport->send_credentials_pending = !transport->is_server;
transport->receive_credentials_pending = transport->is_server;
transport->address = address_copy;
-
- transport->unix_user_function = NULL;
- transport->unix_user_data = NULL;
- transport->free_unix_user_data = NULL;
- transport->windows_user_function = NULL;
- transport->windows_user_data = NULL;
- transport->free_windows_user_data = NULL;
-
transport->expected_guid = NULL;
/* Try to default to something that won't totally hose the system,
*/
transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
+ /* On Linux RLIMIT_NOFILE defaults to 1024, so allowing 4096 fds live
+ should be more than enough */
+ transport->max_live_messages_unix_fds = 4096;
+
/* credentials read from socket if any */
transport->credentials = creds;
-
- _dbus_counter_set_notify (transport->live_messages_size,
+
+ _dbus_counter_set_notify (transport->live_messages,
transport->max_live_messages_size,
- live_messages_size_notify,
+ transport->max_live_messages_unix_fds,
+ live_messages_notify,
transport);
if (transport->address)
_dbus_verbose ("Initialized transport on address %s\n", transport->address);
-
+
+ /* we can have authorization data set only in server mode */
+ _dbus_assert ((transport->is_server && transport->authorization != NULL) ||
+ (!transport->is_server && transport->authorization == NULL));
+
return TRUE;
}
if (!transport->disconnected)
_dbus_transport_disconnect (transport);
- if (transport->free_unix_user_data != NULL)
- (* transport->free_unix_user_data) (transport->unix_user_data);
-
- if (transport->free_windows_user_data != NULL)
- (* transport->free_windows_user_data) (transport->windows_user_data);
-
_dbus_message_loader_unref (transport->loader);
_dbus_auth_unref (transport->auth);
- _dbus_counter_set_notify (transport->live_messages_size,
- 0, NULL, NULL);
- _dbus_counter_unref (transport->live_messages_size);
+ if (transport->authorization)
+ _dbus_authorization_unref (transport->authorization);
+ _dbus_counter_set_notify (transport->live_messages,
+ 0, 0, NULL, NULL);
+ _dbus_counter_unref (transport->live_messages);
dbus_free (transport->address);
dbus_free (transport->expected_guid);
if (transport->credentials)
* opened DBusTransport object. If it isn't, returns #NULL
* and sets @p error.
*
+ * @param address the address to be checked.
* @param error address where an error can be returned.
* @returns a new transport, or #NULL on failure.
*/
int len, i;
_dbus_assert (address != NULL);
- _dbus_assert (*address != '\0');
if (!dbus_parse_address (address, &entries, &len, error))
return NULL; /* not a valid address */
* Creates a new transport for the "autostart" method.
* This creates a client-side of a transport.
*
+ * @param scope scope of autolaunch (Windows only)
* @param error address where an error can be returned.
* @returns a new transport, or #NULL on failure.
*/
static DBusTransport*
-_dbus_transport_new_for_autolaunch (DBusError *error)
+_dbus_transport_new_for_autolaunch (const char *scope, DBusError *error)
{
DBusString address;
DBusTransport *result = NULL;
return NULL;
}
- if (!_dbus_get_autolaunch_address (&address, error))
+ if (!_dbus_get_autolaunch_address (scope, &address, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto out;
if (strcmp (method, "autolaunch") == 0)
{
- *transport_p = _dbus_transport_new_for_autolaunch (error);
+ const char *scope = dbus_address_entry_get_value (entry, "scope");
+
+ *transport_p = _dbus_transport_new_for_autolaunch (scope, error);
if (*transport_p == NULL)
{
{ _dbus_transport_open_socket },
{ _dbus_transport_open_platform_specific },
{ _dbus_transport_open_autolaunch }
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
, { _dbus_transport_open_debug_pipe }
#endif
};
transport->refcount -= 1;
if (transport->refcount == 0)
{
- _dbus_verbose ("%s: finalizing\n", _DBUS_FUNCTION_NAME);
+ _dbus_verbose ("finalizing\n");
_dbus_assert (transport->vtable->finalize != NULL);
void
_dbus_transport_disconnect (DBusTransport *transport)
{
- _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME);
+ _dbus_verbose ("start\n");
_dbus_assert (transport->vtable->disconnect != NULL);
transport->disconnected = TRUE;
- _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
+ _dbus_verbose ("end\n");
}
/**
return !transport->disconnected;
}
-static dbus_bool_t
-auth_via_unix_user_function (DBusTransport *transport)
-{
- DBusCredentials *auth_identity;
- dbus_bool_t allow;
- DBusConnection *connection;
- DBusAllowUnixUserFunction unix_user_function;
- void *unix_user_data;
- dbus_uid_t uid;
-
- /* Dropping the lock here probably isn't that safe. */
-
- auth_identity = _dbus_auth_get_identity (transport->auth);
- _dbus_assert (auth_identity != NULL);
-
- connection = transport->connection;
- unix_user_function = transport->unix_user_function;
- unix_user_data = transport->unix_user_data;
- uid = _dbus_credentials_get_unix_uid (auth_identity);
-
- _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
- _dbus_connection_unlock (connection);
-
- allow = (* unix_user_function) (connection,
- uid,
- unix_user_data);
-
- _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
- _dbus_connection_lock (connection);
-
- if (allow)
- {
- _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
- }
- else
- {
- _dbus_verbose ("Client UID "DBUS_UID_FORMAT
- " was rejected, disconnecting\n",
- _dbus_credentials_get_unix_uid (auth_identity));
- _dbus_transport_disconnect (transport);
- }
-
- return allow;
-}
-
-static dbus_bool_t
-auth_via_windows_user_function (DBusTransport *transport)
+/**
+ * Returns #TRUE if we have been authenticated. It will return #TRUE even if
+ * the transport is now disconnected, but was ever authenticated before
+ * disconnecting.
+ *
+ * This replaces the older _dbus_transport_get_is_authenticated() which
+ * had side-effects.
+ *
+ * @param transport the transport
+ * @returns whether we're authenticated
+ */
+dbus_bool_t
+_dbus_transport_peek_is_authenticated (DBusTransport *transport)
{
- DBusCredentials *auth_identity;
- dbus_bool_t allow;
- DBusConnection *connection;
- DBusAllowWindowsUserFunction windows_user_function;
- void *windows_user_data;
- char *windows_sid;
-
- /* Dropping the lock here probably isn't that safe. */
-
- auth_identity = _dbus_auth_get_identity (transport->auth);
- _dbus_assert (auth_identity != NULL);
-
- connection = transport->connection;
- windows_user_function = transport->windows_user_function;
- windows_user_data = transport->unix_user_data;
- windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
-
- if (windows_sid == NULL)
- {
- /* OOM */
- return FALSE;
- }
-
- _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
- _dbus_connection_unlock (connection);
-
- allow = (* windows_user_function) (connection,
- windows_sid,
- windows_user_data);
-
- _dbus_verbose ("lock %s post windows user function\n", _DBUS_FUNCTION_NAME);
- _dbus_connection_lock (connection);
-
- if (allow)
- {
- _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
- }
- else
- {
- _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
- _dbus_credentials_get_windows_sid (auth_identity));
- _dbus_transport_disconnect (transport);
- }
-
- return allow;
+ return transport->authenticated;
}
-static dbus_bool_t
-auth_via_default_rules (DBusTransport *transport)
-{
- DBusCredentials *auth_identity;
- DBusCredentials *our_identity;
- dbus_bool_t allow;
-
- auth_identity = _dbus_auth_get_identity (transport->auth);
- _dbus_assert (auth_identity != NULL);
-
- /* By default, connection is allowed if the client is 1) root or 2)
- * has the same UID as us or 3) anonymous is allowed.
- */
-
- our_identity = _dbus_credentials_new_from_current_process ();
- if (our_identity == NULL)
- {
- /* OOM */
- return FALSE;
- }
-
- if (transport->allow_anonymous ||
- _dbus_credentials_get_unix_uid (auth_identity) == 0 ||
- _dbus_credentials_same_user (our_identity,
- auth_identity))
- {
- if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
- _dbus_verbose ("Client authorized as SID '%s'"
- "matching our SID '%s'\n",
- _dbus_credentials_get_windows_sid(auth_identity),
- _dbus_credentials_get_windows_sid(our_identity));
- else
- _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
- " matching our UID "DBUS_UID_FORMAT"\n",
- _dbus_credentials_get_unix_uid(auth_identity),
- _dbus_credentials_get_unix_uid(our_identity));
- /* We have authenticated! */
- allow = TRUE;
- }
- else
- {
- if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
- _dbus_verbose ("Client authorized as SID '%s'"
- " but our SID is '%s', disconnecting\n",
- _dbus_credentials_get_windows_sid(our_identity),
- _dbus_credentials_get_windows_sid(our_identity));
- else
- _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
- " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
- _dbus_credentials_get_unix_uid(our_identity),
- _dbus_credentials_get_unix_uid(our_identity));
- _dbus_transport_disconnect (transport);
- allow = FALSE;
- }
-
- _dbus_credentials_unref (our_identity);
-
- return allow;
-}
-
-
/**
- * Returns #TRUE if we have been authenticated. Will return #TRUE
- * even if the transport is disconnected.
+ * Returns #TRUE if we have been authenticated. It will return #TRUE even if
+ * the transport is now disconnected, but was ever authenticated before
+ * disconnecting.
+ *
+ * If we have not finished authenticating, but we have enough buffered input
+ * to finish the job, then this function will do so before it returns.
+ *
+ * This used to be called _dbus_transport_get_is_authenticated(), but that
+ * name seems inappropriate for a function with side-effects.
*
* @todo we drop connection->mutex when calling the unix_user_function,
* and windows_user_function, which may not be safe really.
* @returns whether we're authenticated
*/
dbus_bool_t
-_dbus_transport_get_is_authenticated (DBusTransport *transport)
+_dbus_transport_try_to_authenticate (DBusTransport *transport)
{
if (transport->authenticated)
return TRUE;
_dbus_connection_unref_unlocked (transport->connection);
return FALSE;
}
-
- if (transport->expected_guid == NULL)
- {
- transport->expected_guid = _dbus_strdup (server_guid);
-
- if (transport->expected_guid == NULL)
- {
- _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME);
- return FALSE;
- }
- }
}
/* If we're the server, see if we want to allow this identity to proceed.
*/
if (maybe_authenticated && transport->is_server)
{
- dbus_bool_t allow;
DBusCredentials *auth_identity;
-
+
auth_identity = _dbus_auth_get_identity (transport->auth);
_dbus_assert (auth_identity != NULL);
- /* If we have an auth'd user and a user function, delegate
- * deciding whether auth credentials are good enough to the
- * app; otherwise, use our default decision process.
- */
- if (transport->unix_user_function != NULL &&
- _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
- {
- allow = auth_via_unix_user_function (transport);
- }
- else if (transport->windows_user_function != NULL &&
- _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
- {
- allow = auth_via_windows_user_function (transport);
- }
- else
+ /* If we have an authenticated user, delegate deciding whether auth
+ * credentials are good enough to the app */
+ if (!_dbus_authorization_do_authorization (transport->authorization, auth_identity))
{
- allow = auth_via_default_rules (transport);
+ _dbus_transport_disconnect (transport);
+ maybe_authenticated = FALSE;
}
-
- if (!allow)
- maybe_authenticated = FALSE;
}
transport->authenticated = maybe_authenticated;
}
/**
+ * Returns TRUE if the transport supports sending unix fds.
+ *
+ * @param transport the transport
+ * @returns #TRUE if TRUE it is possible to send unix fds across the transport.
+ */
+dbus_bool_t
+_dbus_transport_can_pass_unix_fd(DBusTransport *transport)
+{
+ return DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport);
+}
+
+/**
* Gets the address of a transport. It will be
* #NULL for a server-side transport.
*
{
if (transport->is_server)
return NULL;
+ else if (transport->authenticated)
+ return _dbus_auth_get_guid_from_server (transport->auth);
else
return transport->expected_guid;
}
_dbus_assert (transport->connection == NULL);
transport->connection = connection;
+ if (transport->is_server)
+ _dbus_authorization_set_connection (transport->authorization, connection);
_dbus_transport_ref (transport);
if (!(* transport->vtable->connection_set) (transport))
timeout_milliseconds);
_dbus_transport_unref (transport);
- _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
+ _dbus_verbose ("end\n");
}
static dbus_bool_t
DBusDispatchStatus
_dbus_transport_get_dispatch_status (DBusTransport *transport)
{
- if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size)
+ if (_dbus_counter_get_size_value (transport->live_messages) >= transport->max_live_messages_size ||
+ _dbus_counter_get_unix_fd_value (transport->live_messages) >= transport->max_live_messages_unix_fds)
return DBUS_DISPATCH_COMPLETE; /* complete for now */
- if (!_dbus_transport_get_is_authenticated (transport))
+ if (!_dbus_transport_try_to_authenticate (transport))
{
if (_dbus_auth_do_work (transport->auth) ==
DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
return DBUS_DISPATCH_NEED_MEMORY;
- else if (!_dbus_transport_get_is_authenticated (transport))
+ else if (!_dbus_transport_try_to_authenticate (transport))
return DBUS_DISPATCH_COMPLETE;
}
_dbus_verbose ("queueing received message %p\n", message);
- if (!_dbus_message_add_size_counter (message, transport->live_messages_size))
+ if (!_dbus_message_add_counter (message, transport->live_messages))
{
_dbus_message_loader_putback_message_link (transport->loader,
link);
}
else
{
+ /* We didn't call the notify function when we added the counter, so
+ * catch up now. Since we have the connection's lock, it's desirable
+ * that we bypass the notify function and call this virtual method
+ * directly. */
+ if (transport->vtable->live_messages_changed)
+ (* transport->vtable->live_messages_changed) (transport);
+
/* pass ownership of link and message ref to connection */
_dbus_connection_queue_received_message_link (transport->connection,
link);
}
/**
+ * See dbus_connection_set_max_message_unix_fds().
+ *
+ * @param transport the transport
+ * @param n the max number of unix fds of a single message
+ */
+void
+_dbus_transport_set_max_message_unix_fds (DBusTransport *transport,
+ long n)
+{
+ _dbus_message_loader_set_max_message_unix_fds (transport->loader, n);
+}
+
+/**
* See dbus_connection_get_max_message_size().
*
* @param transport the transport
}
/**
+ * See dbus_connection_get_max_message_unix_fds().
+ *
+ * @param transport the transport
+ * @returns max message unix fds
+ */
+long
+_dbus_transport_get_max_message_unix_fds (DBusTransport *transport)
+{
+ return _dbus_message_loader_get_max_message_unix_fds (transport->loader);
+}
+
+/**
* See dbus_connection_set_max_received_size().
*
* @param transport the transport
long size)
{
transport->max_live_messages_size = size;
- _dbus_counter_set_notify (transport->live_messages_size,
+ _dbus_counter_set_notify (transport->live_messages,
transport->max_live_messages_size,
- live_messages_size_notify,
+ transport->max_live_messages_unix_fds,
+ live_messages_notify,
transport);
}
+/**
+ * See dbus_connection_set_max_received_unix_fds().
+ *
+ * @param transport the transport
+ * @param n the max unix fds of all incoming messages
+ */
+void
+_dbus_transport_set_max_received_unix_fds (DBusTransport *transport,
+ long n)
+{
+ transport->max_live_messages_unix_fds = n;
+ _dbus_counter_set_notify (transport->live_messages,
+ transport->max_live_messages_size,
+ transport->max_live_messages_unix_fds,
+ live_messages_notify,
+ transport);
+}
/**
* See dbus_connection_get_max_received_size().
}
/**
+ * See dbus_connection_set_max_received_unix_fds().
+ *
+ * @param transport the transport
+ * @returns max unix fds for all live messages
+ */
+long
+_dbus_transport_get_max_received_unix_fds (DBusTransport *transport)
+{
+ return transport->max_live_messages_unix_fds;
+}
+
+/**
* See dbus_connection_get_unix_user().
*
* @param transport the transport
if (_dbus_credentials_include (auth_identity,
DBUS_CREDENTIAL_UNIX_PROCESS_ID))
{
- *pid = _dbus_credentials_get_unix_pid (auth_identity);
+ *pid = _dbus_credentials_get_pid (auth_identity);
return TRUE;
}
else
* @param old_data the old user data to be freed
* @param old_free_data_function old free data function to free it with
*/
-void
+inline void
_dbus_transport_set_unix_user_function (DBusTransport *transport,
DBusAllowUnixUserFunction function,
void *data,
DBusFreeFunction free_data_function,
void **old_data,
DBusFreeFunction *old_free_data_function)
-{
- *old_data = transport->unix_user_data;
- *old_free_data_function = transport->free_unix_user_data;
-
- transport->unix_user_function = function;
- transport->unix_user_data = data;
- transport->free_unix_user_data = free_data_function;
+{
+ if (transport->is_server)
+ _dbus_authorization_set_unix_authorization_callback (transport->authorization, function,
+ data, free_data_function, old_data, old_free_data_function);
}
/**
* @param old_free_data_function old free data function to free it with
*/
-void
+inline void
_dbus_transport_set_windows_user_function (DBusTransport *transport,
DBusAllowWindowsUserFunction function,
void *data,
void **old_data,
DBusFreeFunction *old_free_data_function)
{
- *old_data = transport->windows_user_data;
- *old_free_data_function = transport->free_windows_user_data;
-
- transport->windows_user_function = function;
- transport->windows_user_data = data;
- transport->free_windows_user_data = free_data_function;
+ if (transport->is_server)
+ _dbus_authorization_set_windows_authorization_callback (transport->authorization, function,
+ data, free_data_function, old_data, old_free_data_function);
}
/**
* @param transport the transport
* @param value #TRUE to allow anonymous connection
*/
-void
+inline void
_dbus_transport_set_allow_anonymous (DBusTransport *transport,
dbus_bool_t value)
{
- transport->allow_anonymous = value != FALSE;
+ if (transport->is_server)
+ _dbus_authorization_set_allow_anonymous (transport->authorization, value);
+}
+
+#ifdef DBUS_ENABLE_STATS
+void
+_dbus_transport_get_stats (DBusTransport *transport,
+ dbus_uint32_t *queue_bytes,
+ dbus_uint32_t *queue_fds,
+ dbus_uint32_t *peak_queue_bytes,
+ dbus_uint32_t *peak_queue_fds)
+{
+ if (queue_bytes != NULL)
+ *queue_bytes = _dbus_counter_get_size_value (transport->live_messages);
+
+ if (queue_fds != NULL)
+ *queue_fds = _dbus_counter_get_unix_fd_value (transport->live_messages);
+
+ if (peak_queue_bytes != NULL)
+ *peak_queue_bytes = _dbus_counter_get_peak_size_value (transport->live_messages);
+
+ if (peak_queue_fds != NULL)
+ *peak_queue_fds = _dbus_counter_get_peak_unix_fd_value (transport->live_messages);
}
+#endif /* DBUS_ENABLE_STATS */
/** @} */