Commit 01af5ff4 authored by Havoc Pennington's avatar Havoc Pennington

2003-01-04 Havoc Pennington <hp@pobox.com>

	* test/watch.c (error_handler): make it safe if the error handler
	is called multiple times (if we s/error handler/disconnect
	handler/ we should just guarantee it's called only once)

	* dbus/dbus-transport.c (_dbus_transport_disconnect): call the
	error handler on disconnect (it's quite possible we should
	just change the error handler to a "disconnect handler," I'm
	not sure we have any other meaningful errors)

	* configure.in: check for getpwnam_r

	* dbus/dbus-transport.c, dbus/dbus-transport-unix.c,
	dbus/dbus-auth.c: add credentials support, add EXTERNAL auth
	mechanism as in SASL spec, using socket credentials

	* dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): new function
	(_dbus_send_credentials_unix_socket): new function

	* dbus/dbus-sysdeps.c (_dbus_accept_unix_socket): rename just
	dbus_accept()
	(_dbus_write): only check errno if <0 returned
	(_dbus_write_two): ditto
parent 1ed128b5
2003-01-04 Havoc Pennington <hp@pobox.com>
* test/watch.c (error_handler): make it safe if the error handler
is called multiple times (if we s/error handler/disconnect
handler/ we should just guarantee it's called only once)
* dbus/dbus-transport.c (_dbus_transport_disconnect): call the
error handler on disconnect (it's quite possible we should
just change the error handler to a "disconnect handler," I'm
not sure we have any other meaningful errors)
* configure.in: check for getpwnam_r
* dbus/dbus-transport.c, dbus/dbus-transport-unix.c,
dbus/dbus-auth.c: add credentials support, add EXTERNAL auth
mechanism as in SASL spec, using socket credentials
* dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): new function
(_dbus_send_credentials_unix_socket): new function
* dbus/dbus-sysdeps.c (_dbus_accept_unix_socket): rename just
dbus_accept()
(_dbus_write): only check errno if <0 returned
(_dbus_write_two): ditto
2003-01-02 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-marshal.c: (_dbus_marshal_utf8_string),
......
......@@ -101,7 +101,7 @@ AC_CHECK_SIZEOF(__int64)
## byte order
AC_C_BIGENDIAN
AC_CHECK_FUNCS(vsnprintf vasprintf)
AC_CHECK_FUNCS(vsnprintf vasprintf getpwnam_r)
dnl check for writev header and writev function so we're
dnl good to go if HAVE_WRITEV gets defined.
......
This diff is collapsed.
......@@ -26,6 +26,7 @@
#include <dbus/dbus-macros.h>
#include <dbus/dbus-errors.h>
#include <dbus/dbus-string.h>
#include <dbus/dbus-sysdeps.h>
DBUS_BEGIN_DECLS;
......@@ -43,26 +44,30 @@ typedef enum
DBusAuth* _dbus_auth_server_new (void);
DBusAuth* _dbus_auth_client_new (void);
void _dbus_auth_ref (DBusAuth *auth);
void _dbus_auth_unref (DBusAuth *auth);
DBusAuthState _dbus_auth_do_work (DBusAuth *auth);
dbus_bool_t _dbus_auth_get_bytes_to_send (DBusAuth *auth,
const DBusString **str);
void _dbus_auth_bytes_sent (DBusAuth *auth,
int bytes_sent);
dbus_bool_t _dbus_auth_bytes_received (DBusAuth *auth,
const DBusString *str);
dbus_bool_t _dbus_auth_get_unused_bytes (DBusAuth *auth,
DBusString *str);
dbus_bool_t _dbus_auth_needs_encoding (DBusAuth *auth);
dbus_bool_t _dbus_auth_encode_data (DBusAuth *auth,
const DBusString *plaintext,
DBusString *encoded);
dbus_bool_t _dbus_auth_needs_decoding (DBusAuth *auth);
dbus_bool_t _dbus_auth_decode_data (DBusAuth *auth,
const DBusString *encoded,
DBusString *plaintext);
void _dbus_auth_ref (DBusAuth *auth);
void _dbus_auth_unref (DBusAuth *auth);
DBusAuthState _dbus_auth_do_work (DBusAuth *auth);
dbus_bool_t _dbus_auth_get_bytes_to_send (DBusAuth *auth,
const DBusString **str);
void _dbus_auth_bytes_sent (DBusAuth *auth,
int bytes_sent);
dbus_bool_t _dbus_auth_bytes_received (DBusAuth *auth,
const DBusString *str);
dbus_bool_t _dbus_auth_get_unused_bytes (DBusAuth *auth,
DBusString *str);
dbus_bool_t _dbus_auth_needs_encoding (DBusAuth *auth);
dbus_bool_t _dbus_auth_encode_data (DBusAuth *auth,
const DBusString *plaintext,
DBusString *encoded);
dbus_bool_t _dbus_auth_needs_decoding (DBusAuth *auth);
dbus_bool_t _dbus_auth_decode_data (DBusAuth *auth,
const DBusString *encoded,
DBusString *plaintext);
void _dbus_auth_set_credentials (DBusAuth *auth,
const DBusCredentials *credentials);
void _dbus_auth_get_identity (DBusAuth *auth,
DBusCredentials *credentials);
DBUS_END_DECLS;
......
......@@ -128,7 +128,7 @@ unix_handle_watch (DBusServer *server,
listen_fd = dbus_watch_get_fd (watch);
client_fd = _dbus_accept_unix_socket (listen_fd);
client_fd = _dbus_accept (listen_fd);
if (client_fd < 0)
{
......
This diff is collapsed.
......@@ -65,12 +65,36 @@ int _dbus_write_two (int fd,
int start2,
int len2);
typedef struct
{
/* -1 if not available */
int pid;
int uid;
int gid;
} DBusCredentials;
int _dbus_connect_unix_socket (const char *path,
DBusResultCode *result);
int _dbus_listen_unix_socket (const char *path,
DBusResultCode *result);
int _dbus_accept_unix_socket (int listen_fd);
int _dbus_accept (int listen_fd);
dbus_bool_t _dbus_read_credentials_unix_socket (int client_fd,
DBusCredentials *credentials,
DBusResultCode *result);
dbus_bool_t _dbus_send_credentials_unix_socket (int server_fd,
DBusResultCode *result);
dbus_bool_t _dbus_credentials_from_username (const DBusString *username,
DBusCredentials *credentials);
dbus_bool_t _dbus_credentials_from_uid_string (const DBusString *uid_str,
DBusCredentials *credentials);
void _dbus_credentials_from_current_process (DBusCredentials *credentials);
dbus_bool_t _dbus_credentials_match (const DBusCredentials *expected_credentials,
const DBusCredentials *provided_credentials);
dbus_bool_t _dbus_string_append_our_uid (DBusString *str);
DBUS_END_DECLS;
......
......@@ -77,9 +77,14 @@ struct DBusTransport
DBusAuth *auth; /**< Authentication conversation */
DBusCredentials credentials; /**< Credentials of other end */
unsigned int disconnected : 1; /**< #TRUE if we are disconnected. */
unsigned int authenticated : 1; /**< Cache of auth state; use _dbus_transport_get_is_authenticated() to query value */
unsigned int messages_need_sending : 1; /**< #TRUE if we need to write messages out */
unsigned int send_credentials_pending : 1; /**< #TRUE if we need to send credentials */
unsigned int receive_credentials_pending : 1; /**< #TRUE if we need to receive credentials */
unsigned int is_server : 1; /**< #TRUE if on the server side */
};
dbus_bool_t _dbus_transport_init_base (DBusTransport *transport,
......
......@@ -123,7 +123,8 @@ check_write_watch (DBusTransport *transport)
if (_dbus_transport_get_is_authenticated (transport))
need_write_watch = transport->messages_need_sending;
else
need_write_watch = _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
need_write_watch = transport->send_credentials_pending ||
_dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
if (transport->disconnected)
need_write_watch = FALSE;
......@@ -390,16 +391,71 @@ recover_unused_bytes (DBusTransport *transport)
do_io_error (transport);
}
static void
exchange_credentials (DBusTransport *transport,
dbus_bool_t do_reading,
dbus_bool_t do_writing)
{
DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
if (do_writing && transport->send_credentials_pending)
{
if (_dbus_send_credentials_unix_socket (unix_transport->fd,
NULL))
{
transport->send_credentials_pending = FALSE;
}
else
{
_dbus_verbose ("Failed to write credentials\n");
do_io_error (transport);
}
}
if (do_reading && transport->receive_credentials_pending)
{
if (_dbus_read_credentials_unix_socket (unix_transport->fd,
&transport->credentials,
NULL))
{
transport->receive_credentials_pending = FALSE;
}
else
{
_dbus_verbose ("Failed to read credentials\n");
do_io_error (transport);
}
}
if (!(transport->send_credentials_pending ||
transport->receive_credentials_pending))
{
_dbus_auth_set_credentials (transport->auth,
&transport->credentials);
}
}
static void
do_authentication (DBusTransport *transport,
dbus_bool_t do_reading,
dbus_bool_t do_writing)
{
{
_dbus_transport_ref (transport);
while (!_dbus_transport_get_is_authenticated (transport) &&
_dbus_transport_get_is_connected (transport))
{
exchange_credentials (transport, do_reading, do_writing);
if (transport->send_credentials_pending ||
transport->receive_credentials_pending)
{
_dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n",
transport->send_credentials_pending,
transport->receive_credentials_pending);
goto out;
}
switch (_dbus_auth_do_work (transport->auth))
{
case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
......@@ -963,7 +1019,7 @@ _dbus_transport_new_for_domain_socket (const char *path,
close (fd);
fd = -1;
}
return transport;
}
......
......@@ -105,6 +105,13 @@ _dbus_transport_init_base (DBusTransport *transport,
transport->authenticated = FALSE;
transport->messages_need_sending = FALSE;
transport->disconnected = FALSE;
transport->send_credentials_pending = !server;
transport->receive_credentials_pending = server;
transport->is_server = server;
transport->credentials.pid = -1;
transport->credentials.uid = -1;
transport->credentials.gid = -1;
return TRUE;
}
......@@ -205,8 +212,12 @@ _dbus_transport_disconnect (DBusTransport *transport)
DBUS_TRANSPORT_HOLD_REF (transport);
(* transport->vtable->disconnect) (transport);
transport->disconnected = TRUE;
_dbus_connection_transport_error (transport->connection,
DBUS_RESULT_DISCONNECTED);
DBUS_TRANSPORT_RELEASE_REF (transport);
}
......@@ -238,9 +249,45 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
return TRUE;
else
{
if (transport->disconnected)
return FALSE;
transport->authenticated =
(!(transport->send_credentials_pending ||
transport->receive_credentials_pending)) &&
_dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_AUTHENTICATED;
/* If we've authenticated as some identity, check that the auth
* identity is the same as our own identity. In the future, we
* may have API allowing applications to specify how this is
* done, for example they may allow connection as any identity,
* but then impose restrictions on certain identities.
* Or they may give certain identities extra privileges.
*/
if (transport->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))
{
_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);
}
}
return transport->authenticated;
}
}
......
......@@ -19,7 +19,7 @@ The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
in this document are to be interpreted as defined in "Key words for
use in RFCs to Indicate Requirement Levels" [RFC 2119]
Overview
Protocol Overview
===
The protocol is a line-based protocol, where each line ends with
......@@ -52,6 +52,27 @@ From server to client are as follows:
ERROR
Special credentials-passing nul byte
===
Immediately after connecting to the server, the client must send a
single nul byte. This byte may be accompanied by credentials
information on some operating systems that use sendmsg() with
SCM_CREDS or SCM_CREDENTIALS to pass credentials over UNIX domain
sockets. However, the nul byte MUST be sent even on other kinds of
socket, and even on operating systems that do not require a byte to be
sent in order to transmit credentials. The text protocol described in
this document begins after the single nul byte. If the first byte
received from the client is not a nul byte, the server may disconnect
that client.
A nul byte in any context other than the initial byte is an error;
the protocol is ASCII-only.
The credentials sent along with the nul byte may be used with the
SASL mechanism EXTERNAL.
AUTH Command
===
......
......@@ -305,6 +305,9 @@ error_handler (DBusConnection *connection,
"Error on connection: %s\n",
dbus_result_to_string (error_code));
/* we don't want to be called again since we're dropping the connection */
dbus_connection_set_error_function (connection, NULL, NULL, NULL);
_dbus_list_remove (&connections, connection);
dbus_connection_unref (connection);
quit_mainloop ();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment