* @param transport the transport being created.
* @param vtable the subclass vtable.
* @param server #TRUE if this transport is on the server side of a connection
+ * @param address the address of the transport
* @returns #TRUE on success.
*/
dbus_bool_t
_dbus_transport_init_base (DBusTransport *transport,
const DBusTransportVTable *vtable,
- dbus_bool_t server)
+ dbus_bool_t server,
+ const DBusString *address)
{
DBusMessageLoader *loader;
DBusAuth *auth;
DBusCounter *counter;
+ char *address_copy;
loader = _dbus_message_loader_new ();
if (loader == NULL)
_dbus_auth_unref (auth);
_dbus_message_loader_unref (loader);
return FALSE;
+ }
+
+ if (server)
+ {
+ _dbus_assert (address == NULL);
+ address_copy = NULL;
+ }
+ else
+ {
+ _dbus_assert (address != NULL);
+
+ if (!_dbus_string_copy_data (address, &address_copy))
+ {
+ _dbus_counter_unref (counter);
+ _dbus_auth_unref (auth);
+ _dbus_message_loader_unref (loader);
+ return FALSE;
+ }
}
transport->refcount = 1;
transport->send_credentials_pending = !server;
transport->receive_credentials_pending = server;
transport->is_server = server;
-
+ transport->address = address_copy;
+
+ transport->unix_user_function = NULL;
+ transport->unix_user_data = NULL;
+ transport->free_unix_user_data = NULL;
+
/* Try to default to something that won't totally hose the system,
* but doesn't impose too much of a limitation.
*/
transport->max_live_messages_size,
live_messages_size_notify,
transport);
+
+ if (transport->address)
+ _dbus_verbose ("Initialized transport on address %s\n", transport->address);
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);
_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);
+ dbus_free (transport->address);
}
/**
* DBusResultCode is a bit limiting here.
*
* @param address the address.
- * @param result location to store reason for failure.
+ * @param error location to store reason for failure.
* @returns new transport of #NULL on failure.
*/
DBusTransport*
_dbus_transport_open (const char *address,
- DBusResultCode *result)
+ DBusError *error)
{
DBusTransport *transport;
DBusAddressEntry **entries;
int len, i;
+ const char *address_problem_type;
+ const char *address_problem_field;
+ const char *address_problem_other;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
- if (!dbus_parse_address (address, &entries, &len, result))
+ if (!dbus_parse_address (address, &entries, &len, error))
return NULL;
transport = NULL;
+ address_problem_type = NULL;
+ address_problem_field = NULL;
+ address_problem_other = NULL;
for (i = 0; i < len; i++)
{
const char *path = dbus_address_entry_get_value (entries[i], "path");
if (path == NULL)
- goto bad_address;
+ {
+ address_problem_type = "unix";
+ address_problem_field = "path";
+ goto bad_address;
+ }
- transport = _dbus_transport_new_for_domain_socket (path, FALSE, result);
+ transport = _dbus_transport_new_for_domain_socket (path, error);
}
else if (strcmp (method, "tcp") == 0)
{
long lport;
dbus_bool_t sresult;
- if (port == NULL)
- goto bad_address;
+ if (port == NULL)
+ {
+ address_problem_type = "tcp";
+ address_problem_field = "port";
+ goto bad_address;
+ }
_dbus_string_init_const (&str, port);
sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
_dbus_string_free (&str);
if (sresult == FALSE || lport <= 0 || lport > 65535)
- goto bad_address;
+ {
+ address_problem_other = "Port is not an integer between 0 and 65535";
+ goto bad_address;
+ }
- transport = _dbus_transport_new_for_tcp_socket (host, lport, FALSE, result);
+ transport = _dbus_transport_new_for_tcp_socket (host, lport, error);
}
#ifdef DBUS_BUILD_TESTS
else if (strcmp (method, "debug") == 0)
const char *name = dbus_address_entry_get_value (entries[i], "name");
if (name == NULL)
- goto bad_address;
+ {
+ address_problem_type = "debug";
+ address_problem_field = "name";
+ goto bad_address;
+ }
- transport = _dbus_transport_debug_client_new (name, result);
+ transport = _dbus_transport_debug_client_new (name, error);
}
else if (strcmp (method, "debug-pipe") == 0)
{
const char *name = dbus_address_entry_get_value (entries[i], "name");
- if (name == NULL)
- goto bad_address;
+ if (name == NULL)
+ {
+ address_problem_type = "debug-pipe";
+ address_problem_field = "name";
+ goto bad_address;
+ }
- transport = _dbus_transport_debug_pipe_new (name, result);
+ transport = _dbus_transport_debug_pipe_new (name, error);
}
#endif
else
- goto bad_address;
+ {
+ address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
+ goto bad_address;
+ }
if (transport)
break;
bad_address:
dbus_address_entries_free (entries);
- dbus_set_result (result, DBUS_RESULT_BAD_ADDRESS);
+
+ if (address_problem_type != NULL)
+ dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+ "Address of type %s was missing argument %s",
+ address_problem_type, address_problem_field);
+ else
+ dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+ "Could not parse address: %s",
+ address_problem_other);
return NULL;
}
* Returns #TRUE if we have been authenticated. Will return #TRUE
* even if the transport is disconnected.
*
+ * @todo needs to drop connection->mutex when calling the unix_user_function
+ *
* @param transport the transport
* @returns whether we're authenticated
*/
return TRUE;
else
{
+ dbus_bool_t maybe_authenticated;
+
if (transport->disconnected)
return FALSE;
- transport->authenticated =
+ maybe_authenticated =
(!(transport->send_credentials_pending ||
transport->receive_credentials_pending)) &&
_dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_AUTHENTICATED;
* Or they may give certain identities extra privileges.
*/
- if (transport->authenticated && transport->is_server)
+ if (maybe_authenticated && transport->is_server)
{
DBusCredentials auth_identity;
- DBusCredentials our_identity;
- _dbus_credentials_from_current_process (&our_identity);
_dbus_auth_get_identity (transport->auth, &auth_identity);
-
- if (!_dbus_credentials_match (&our_identity,
- &auth_identity))
+
+ if (transport->unix_user_function != NULL)
{
- _dbus_verbose ("Client authorized as UID %d but our UID is %d, disconnecting\n",
- auth_identity.uid, our_identity.uid);
- _dbus_transport_disconnect (transport);
- return FALSE;
+ /* FIXME we hold the connection lock here and should drop it */
+ if (!(* transport->unix_user_function) (transport->connection,
+ auth_identity.uid,
+ transport->unix_user_data))
+ {
+ _dbus_verbose ("Client UID %d was rejected, disconnecting\n",
+ auth_identity.uid);
+ _dbus_transport_disconnect (transport);
+ return FALSE;
+ }
+ else
+ {
+ _dbus_verbose ("Client UID %d authorized\n", auth_identity.uid);
+ }
}
else
{
- _dbus_verbose ("Client authorized as UID %d matching our UID %d\n",
- auth_identity.uid, our_identity.uid);
+ DBusCredentials our_identity;
+
+ _dbus_credentials_from_current_process (&our_identity);
+
+ if (!_dbus_credentials_match (&our_identity,
+ &auth_identity))
+ {
+ _dbus_verbose ("Client authorized as UID %d but our UID is %d, disconnecting\n",
+ auth_identity.uid, our_identity.uid);
+ _dbus_transport_disconnect (transport);
+ return FALSE;
+ }
+ else
+ {
+ _dbus_verbose ("Client authorized as UID %d matching our UID %d\n",
+ auth_identity.uid, our_identity.uid);
+ }
}
}
+
+ transport->authenticated = maybe_authenticated;
return transport->authenticated;
}
}
/**
+ * Gets the address of a transport. It will be
+ * #NULL for a server-side transport.
+ *
+ * @param transport the transport
+ * @returns transport's address
+ */
+const char*
+_dbus_transport_get_address (DBusTransport *transport)
+{
+ return transport->address;
+}
+
+/**
* Handles a watch by reading data, writing data, or disconnecting
* the transport, as appropriate for the given condition.
*
DBusString *buffer;
int orig_len;
- if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&plaintext))
goto nomem;
_dbus_auth_get_unused_bytes (transport->auth,
return transport->max_live_messages_size;
}
+/**
+ * See dbus_connection_get_unix_user().
+ *
+ * @param transport the transport
+ * @param uid return location for the user ID
+ * @returns #TRUE if uid is filled in with a valid user ID
+ */
+dbus_bool_t
+_dbus_transport_get_unix_user (DBusTransport *transport,
+ unsigned long *uid)
+{
+ DBusCredentials auth_identity;
+
+ *uid = _DBUS_INT_MAX; /* better than some root or system user in
+ * case of bugs in the caller. Caller should
+ * never use this value on purpose, however.
+ */
+
+ if (!transport->authenticated)
+ return FALSE;
+
+ _dbus_auth_get_identity (transport->auth, &auth_identity);
+
+ if (auth_identity.uid >= 0)
+ {
+ *uid = auth_identity.uid;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/**
+ * See dbus_connection_set_unix_user_function().
+ *
+ * @param transport the transport
+ * @param function the predicate
+ * @param data data to pass to the predicate
+ * @param free_data_function function to free the data
+ * @param old_data the old user data to be freed
+ * @param old_free_data_function old free data function to free it with
+ */
+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;
+}
+
/** @} */