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

* test/data/auth/*: adapt to changes

	* dbus/dbus-auth-script.c (_dbus_auth_script_run): add
	USERID_BASE64 and change USERNAME_BASE64 to put in username not
	userid

	* dbus/dbus-keyring.c (_dbus_keyring_validate_context): prevent
	more stuff from being in a context name, to make the protocol
	simpler to deal with

	* dbus/dbus-errors.c (dbus_error_has_name): new function
	(dbus_error_is_set): new function

	* dbus/dbus-auth.c: replace DBUS_STUPID_TEST_MECH auth
	with DBUS_COOKIE_SHA1, implement DBUS_COOKIE_SHA1

	* dbus/dbus-connection.c (dbus_connection_flush): also read
	messages during a flush operation

	* dbus/Makefile.am: remove dbus-md5 since it isn't currently used.
This commit is contained in:
Havoc Pennington 2003-03-05 02:01:34 +00:00
parent 6bea42d2b8
commit 7e050c8871
21 changed files with 1115 additions and 147 deletions

View file

@ -1,3 +1,26 @@
2003-03-04 Havoc Pennington <hp@pobox.com>
* test/data/auth/*: adapt to changes
* dbus/dbus-auth-script.c (_dbus_auth_script_run): add
USERID_BASE64 and change USERNAME_BASE64 to put in username not
userid
* dbus/dbus-keyring.c (_dbus_keyring_validate_context): prevent
more stuff from being in a context name, to make the protocol
simpler to deal with
* dbus/dbus-errors.c (dbus_error_has_name): new function
(dbus_error_is_set): new function
* dbus/dbus-auth.c: replace DBUS_STUPID_TEST_MECH auth
with DBUS_COOKIE_SHA1, implement DBUS_COOKIE_SHA1
* dbus/dbus-connection.c (dbus_connection_flush): also read
messages during a flush operation
* dbus/Makefile.am: remove dbus-md5 since it isn't currently used.
2003-03-05 Anders Carlsson <andersca@codefactory.se>
* configure.in: Check for gethostbyname on Solaris.

View file

@ -32,8 +32,6 @@ libdbus_1_la_SOURCES= \
dbus-errors.c \
dbus-keyring.c \
dbus-keyring.h \
dbus-md5.c \
dbus-md5.h \
dbus-memory.c \
dbus-message.c \
dbus-message-handler.c \
@ -63,6 +61,9 @@ libdbus_1_la_SOURCES= \
dbus-watch.c \
dbus-watch.h
## dbus-md5.c \
## dbus-md5.h \
## this library is linked into both libdbus and the bus
## itself, but does not export any symbols from libdbus.

View file

@ -191,9 +191,12 @@ _dbus_auth_script_run (const DBusString *filename)
DBusAuth *auth;
DBusString from_auth;
DBusAuthState state;
DBusString context;
retval = FALSE;
auth = NULL;
_dbus_string_init_const (&context, "org_freedesktop_test");
if (!_dbus_string_init (&file, _DBUS_INT_MAX))
return FALSE;
@ -299,6 +302,7 @@ _dbus_auth_script_run (const DBusString *filename)
_dbus_credentials_from_current_process (&creds);
_dbus_auth_set_credentials (auth, &creds);
_dbus_auth_set_context (auth, &context);
}
else if (auth == NULL)
{
@ -359,15 +363,49 @@ _dbus_auth_script_run (const DBusString *filename)
goto out;
}
/* Replace USERNAME_BASE64 with our username in base64 */
/* Replace USERID_BASE64 with our username in base64 */
{
int where;
if (_dbus_string_find (&to_send, 0,
"USERNAME_BASE64", &where))
"USERID_BASE64", &where))
{
DBusString username;
if (!_dbus_string_init (&username, _DBUS_INT_MAX))
{
_dbus_warn ("no memory for userid\n");
_dbus_string_free (&to_send);
goto out;
}
if (!_dbus_string_append_our_uid (&username))
{
_dbus_warn ("no memory for userid\n");
_dbus_string_free (&username);
_dbus_string_free (&to_send);
goto out;
}
_dbus_string_delete (&to_send, where, strlen ("USERID_BASE64"));
if (!_dbus_string_base64_encode (&username, 0,
&to_send, where))
{
_dbus_warn ("no memory to subst USERID_BASE64\n");
_dbus_string_free (&username);
_dbus_string_free (&to_send);
goto out;
}
_dbus_string_free (&username);
}
else if (_dbus_string_find (&to_send, 0,
"USERNAME_BASE64", &where))
{
DBusString username;
const DBusString *u;
if (!_dbus_string_init (&username, _DBUS_INT_MAX))
{
_dbus_warn ("no memory for username\n");
@ -375,7 +413,9 @@ _dbus_auth_script_run (const DBusString *filename)
goto out;
}
if (!_dbus_string_append_our_uid (&username))
if (!_dbus_user_info_from_current_process (&u, NULL, NULL) ||
!_dbus_string_copy (u, 0, &username,
_dbus_string_get_length (&username)))
{
_dbus_warn ("no memory for username\n");
_dbus_string_free (&username);

View file

@ -24,6 +24,8 @@
#include "dbus-string.h"
#include "dbus-list.h"
#include "dbus-internals.h"
#include "dbus-keyring.h"
#include "dbus-sha.h"
/* See doc/dbus-sasl-profile.txt */
@ -42,6 +44,19 @@
* @todo some SASL profiles require sending the empty string as a
* challenge/response, but we don't currently allow that in our
* protocol.
*
* @todo DBusAuth really needs to be rewritten as an explicit state
* machine. Right now it's too hard to prove to yourself by inspection
* that it works.
*
* @todo right now sometimes both ends will block waiting for input
* from the other end, e.g. if there's an error during
* DBUS_COOKIE_SHA1.
*
* @todo the cookie keyring needs to be cached globally not just
* per-auth (which raises threadsafety issues too)
*
* @todo grep FIXME in dbus-auth.c
*/
/**
@ -132,9 +147,18 @@ struct DBusAuth
* as.
*/
DBusCredentials credentials; /**< Credentials, fields may be -1 */
DBusCredentials credentials; /**< Credentials read from socket,
* fields may be -1
*/
DBusCredentials authorized_identity; /**< Credentials that are authorized */
DBusCredentials desired_identity; /**< Identity client has requested */
DBusString context; /**< Cookie scope */
DBusKeyring *keyring; /**< Keyring for cookie mechanism. */
int cookie_id; /**< ID of cookie to use */
DBusString challenge; /**< Challenge sent to client */
unsigned int needed_memory : 1; /**< We needed memory to continue since last
* successful getting something done
@ -254,6 +278,13 @@ _dbus_auth_new (int size)
auth->authorized_identity.pid = -1;
auth->authorized_identity.uid = -1;
auth->authorized_identity.gid = -1;
auth->desired_identity.pid = -1;
auth->desired_identity.uid = -1;
auth->desired_identity.gid = -1;
auth->keyring = NULL;
auth->cookie_id = -1;
/* note that we don't use the max string length feature,
* because you can't use that feature if you're going to
@ -264,27 +295,39 @@ _dbus_auth_new (int size)
*/
if (!_dbus_string_init (&auth->incoming, _DBUS_INT_MAX))
{
dbus_free (auth);
return NULL;
}
goto enomem_0;
if (!_dbus_string_init (&auth->outgoing, _DBUS_INT_MAX))
{
_dbus_string_free (&auth->incoming);
dbus_free (auth);
return NULL;
}
goto enomem_1;
if (!_dbus_string_init (&auth->identity, _DBUS_INT_MAX))
{
_dbus_string_free (&auth->incoming);
_dbus_string_free (&auth->outgoing);
dbus_free (auth);
return NULL;
}
goto enomem_2;
if (!_dbus_string_init (&auth->context, _DBUS_INT_MAX))
goto enomem_3;
if (!_dbus_string_init (&auth->challenge, _DBUS_INT_MAX))
goto enomem_4;
/* default context if none is specified */
if (!_dbus_string_append (&auth->context, "org_freedesktop_general"))
goto enomem_5;
return auth;
enomem_5:
_dbus_string_free (&auth->challenge);
enomem_4:
_dbus_string_free (&auth->context);
enomem_3:
_dbus_string_free (&auth->identity);
enomem_2:
_dbus_string_free (&auth->incoming);
enomem_1:
_dbus_string_free (&auth->outgoing);
enomem_0:
dbus_free (auth);
return NULL;
}
static void
@ -295,9 +338,14 @@ shutdown_mech (DBusAuth *auth)
auth->authenticated = FALSE;
auth->already_asked_for_initial_response = FALSE;
_dbus_string_set_length (&auth->identity, 0);
auth->authorized_identity.pid = -1;
auth->authorized_identity.uid = -1;
auth->authorized_identity.gid = -1;
auth->desired_identity.pid = -1;
auth->desired_identity.uid = -1;
auth->desired_identity.gid = -1;
if (auth->mech != NULL)
{
@ -313,74 +361,601 @@ shutdown_mech (DBusAuth *auth)
}
}
static dbus_bool_t
handle_server_data_stupid_test_mech (DBusAuth *auth,
const DBusString *data)
{
if (!_dbus_string_append (&auth->outgoing,
"OK\r\n"))
return FALSE;
_dbus_credentials_from_current_process (&auth->authorized_identity);
auth->authenticated_pending_begin = TRUE;
return TRUE;
}
static void
handle_server_shutdown_stupid_test_mech (DBusAuth *auth)
{
}
static dbus_bool_t
handle_client_data_stupid_test_mech (DBusAuth *auth,
const DBusString *data)
{
return TRUE;
}
static void
handle_client_shutdown_stupid_test_mech (DBusAuth *auth)
{
}
/* the stupid test mech is a base64-encoded string;
* all the inefficiency, none of the security!
/* Returns TRUE but with an empty string hash if the
* cookie_id isn't known. As with all this code
* TRUE just means we had enough memory.
*/
static dbus_bool_t
handle_encode_stupid_test_mech (DBusAuth *auth,
const DBusString *plaintext,
DBusString *encoded)
sha1_compute_hash (DBusAuth *auth,
int cookie_id,
const DBusString *server_challenge,
const DBusString *client_challenge,
DBusString *hash)
{
if (!_dbus_string_base64_encode (plaintext, 0, encoded,
_dbus_string_get_length (encoded)))
return FALSE;
DBusString cookie;
DBusString to_hash;
dbus_bool_t retval;
return TRUE;
_dbus_assert (auth->keyring != NULL);
retval = FALSE;
if (!_dbus_string_init (&cookie, _DBUS_INT_MAX))
return FALSE;
if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id,
&cookie))
goto out_0;
if (_dbus_string_get_length (&cookie) == 0)
{
retval = TRUE;
goto out_0;
}
if (!_dbus_string_init (&to_hash, _DBUS_INT_MAX))
goto out_0;
if (!_dbus_string_copy (server_challenge, 0,
&to_hash, _dbus_string_get_length (&to_hash)))
goto out_1;
if (!_dbus_string_append (&to_hash, ":"))
goto out_1;
if (!_dbus_string_copy (client_challenge, 0,
&to_hash, _dbus_string_get_length (&to_hash)))
goto out_1;
if (!_dbus_string_append (&to_hash, ":"))
goto out_1;
if (!_dbus_string_copy (&cookie, 0,
&to_hash, _dbus_string_get_length (&to_hash)))
goto out_1;
if (!_dbus_sha_compute (&to_hash, hash))
goto out_1;
retval = TRUE;
out_1:
_dbus_string_zero (&to_hash);
_dbus_string_free (&to_hash);
out_0:
_dbus_string_zero (&cookie);
_dbus_string_free (&cookie);
return retval;
}
/* http://www.ietf.org/rfc/rfc2831.txt suggests at least 64 bits of
* entropy, we use 128
*/
#define N_CHALLENGE_BYTES (128/8)
static dbus_bool_t
sha1_handle_first_client_response (DBusAuth *auth,
const DBusString *data)
{
/* We haven't sent a challenge yet, we're expecting a desired
* username from the client.
*/
DBusString tmp;
DBusString tmp2;
dbus_bool_t retval;
int old_len;
DBusError error;
retval = FALSE;
_dbus_string_set_length (&auth->challenge, 0);
if (_dbus_string_get_length (data) > 0)
{
if (_dbus_string_get_length (&auth->identity) > 0)
{
/* Tried to send two auth identities, wtf */
_dbus_verbose ("client tried to send auth identity, but we already have one\n");
return send_rejected (auth);
}
else
{
/* this is our auth identity */
if (!_dbus_string_copy (data, 0, &auth->identity, 0))
return FALSE;
}
}
if (!_dbus_credentials_from_username (data, &auth->desired_identity))
{
_dbus_verbose ("Did not get a valid username from client\n");
return send_rejected (auth);
}
if (!_dbus_string_init (&tmp, _DBUS_INT_MAX))
return FALSE;
if (!_dbus_string_init (&tmp2, _DBUS_INT_MAX))
{
_dbus_string_free (&tmp);
return FALSE;
}
old_len = _dbus_string_get_length (&auth->outgoing);
/* we cache the keyring for speed, so here we drop it if it's the
* wrong one. FIXME caching the keyring here is useless since we use
* a different DBusAuth for every connection.
*/
if (auth->keyring &&
!_dbus_keyring_is_for_user (auth->keyring,
data))
{
_dbus_keyring_unref (auth->keyring);
auth->keyring = NULL;
}
if (auth->keyring == NULL)
{
DBusError error;
dbus_error_init (&error);
auth->keyring = _dbus_keyring_new_homedir (data,
&auth->context,
&error);
if (auth->keyring == NULL)
{
if (dbus_error_has_name (&error,
DBUS_ERROR_NO_MEMORY))
{
dbus_error_free (&error);
goto out;
}
else
{
_dbus_assert (dbus_error_is_set (&error));
_dbus_verbose ("Error loading keyring: %s\n",
error.message);
if (send_rejected (auth))
retval = TRUE; /* retval is only about mem */
dbus_error_free (&error);
goto out;
}
}
else
{
_dbus_assert (!dbus_error_is_set (&error));
}
}
_dbus_assert (auth->keyring != NULL);
dbus_error_init (&error);
auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
if (auth->cookie_id < 0)
{
_dbus_assert (dbus_error_is_set (&error));
_dbus_verbose ("Could not get a cookie ID to send to client: %s\n",
error.message);
if (send_rejected (auth))
retval = TRUE;
dbus_error_free (&error);
goto out;
}
else
{
_dbus_assert (!dbus_error_is_set (&error));
}
if (!_dbus_string_copy (&auth->context, 0,
&tmp2, _dbus_string_get_length (&tmp2)))
goto out;
if (!_dbus_string_append (&tmp2, " "))
goto out;
if (!_dbus_string_append_int (&tmp2, auth->cookie_id))
goto out;
if (!_dbus_string_append (&tmp2, " "))
goto out;
if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
goto out;
_dbus_string_set_length (&auth->challenge, 0);
if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
goto out;
if (!_dbus_string_hex_encode (&tmp, 0, &tmp2,
_dbus_string_get_length (&tmp2)))
goto out;
if (!_dbus_string_append (&auth->outgoing,
"DATA "))
goto out;
if (!_dbus_string_base64_encode (&tmp2, 0, &auth->outgoing,
_dbus_string_get_length (&auth->outgoing)))
goto out;
if (!_dbus_string_append (&auth->outgoing,
"\r\n"))
goto out;
retval = TRUE;
out:
_dbus_string_zero (&tmp);
_dbus_string_free (&tmp);
_dbus_string_zero (&tmp2);
_dbus_string_free (&tmp2);
if (!retval)
_dbus_string_set_length (&auth->outgoing, old_len);
return retval;
}
static dbus_bool_t
handle_decode_stupid_test_mech (DBusAuth *auth,
const DBusString *encoded,
DBusString *plaintext)
sha1_handle_second_client_response (DBusAuth *auth,
const DBusString *data)
{
if (!_dbus_string_base64_decode (encoded, 0, plaintext,
_dbus_string_get_length (plaintext)))
return FALSE;
/* We are expecting a response which is the hex-encoded client
* challenge, space, then SHA-1 hash of the concatenation of our
* challenge, ":", client challenge, ":", secret key, all
* hex-encoded.
*/
int i;
DBusString client_challenge;
DBusString client_hash;
dbus_bool_t retval;
DBusString correct_hash;
return TRUE;
retval = FALSE;
if (!_dbus_string_find_blank (data, 0, &i))
{
_dbus_verbose ("no space separator in client response\n");
return send_rejected (auth);
}
if (!_dbus_string_init (&client_challenge, _DBUS_INT_MAX))
goto out_0;
if (!_dbus_string_init (&client_hash, _DBUS_INT_MAX))
goto out_1;
if (!_dbus_string_copy_len (data, 0, i, &client_challenge,
0))
goto out_2;
_dbus_string_skip_blank (data, i, &i);
if (!_dbus_string_copy_len (data, i,
_dbus_string_get_length (data) - i,
&client_hash,
0))
goto out_2;
if (_dbus_string_get_length (&client_challenge) == 0 ||
_dbus_string_get_length (&client_hash) == 0)
{
_dbus_verbose ("zero-length client challenge or hash\n");
if (send_rejected (auth))
retval = TRUE;
goto out_2;
}
if (!_dbus_string_init (&correct_hash, _DBUS_INT_MAX))
goto out_2;
if (!sha1_compute_hash (auth, auth->cookie_id,
&auth->challenge,
&client_challenge,
&correct_hash))
goto out_3;
/* if cookie_id was invalid, then we get an empty hash */
if (_dbus_string_get_length (&correct_hash) == 0)
{
if (send_rejected (auth))
retval = TRUE;
goto out_3;
}
if (!_dbus_string_equal (&client_hash, &correct_hash))
{
if (send_rejected (auth))
retval = TRUE;
goto out_3;
}
if (!_dbus_string_append (&auth->outgoing,
"OK\r\n"))
goto out_3;
_dbus_verbose ("authenticated client with UID %d using DBUS_COOKIE_SHA1\n",
auth->desired_identity.uid);
auth->authorized_identity = auth->desired_identity;
auth->authenticated_pending_begin = TRUE;
retval = TRUE;
out_3:
_dbus_string_zero (&correct_hash);
_dbus_string_free (&correct_hash);
out_2:
_dbus_string_zero (&client_hash);
_dbus_string_free (&client_hash);
out_1:
_dbus_string_free (&client_challenge);
out_0:
return retval;
}
static dbus_bool_t
handle_server_data_cookie_sha1_mech (DBusAuth *auth,
const DBusString *data)
{
if (auth->cookie_id < 0)
return sha1_handle_first_client_response (auth, data);
else
return sha1_handle_second_client_response (auth, data);
}
static void
handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
{
auth->cookie_id = -1;
_dbus_string_set_length (&auth->challenge, 0);
}
static dbus_bool_t
handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth,
DBusString *response)
{
const DBusString *username;
dbus_bool_t retval;
retval = FALSE;
if (!_dbus_user_info_from_current_process (&username,
NULL, NULL))
goto out_0;
if (!_dbus_string_base64_encode (username, 0,
response,
_dbus_string_get_length (response)))
goto out_0;
retval = TRUE;
out_0:
return retval;
}
/* FIXME if we send the server an error, right now both sides
* just hang. Server has to reject on getting an error, or
* client has to cancel. Should be in the spec.
*/
static dbus_bool_t
handle_client_data_cookie_sha1_mech (DBusAuth *auth,
const DBusString *data)
{
/* The data we get from the server should be the cookie context
* name, the cookie ID, and the server challenge, separated by
* spaces. We send back our challenge string and the correct hash.
*/
dbus_bool_t retval;
DBusString context;
DBusString cookie_id_str;
DBusString server_challenge;
DBusString client_challenge;
DBusString correct_hash;
DBusString tmp;
int i, j;
long val;
int old_len;
retval = FALSE;
if (!_dbus_string_find_blank (data, 0, &i))
{
if (_dbus_string_append (&auth->outgoing,
"ERROR \"Server did not send context/ID/challenge properly\"\r\n"))
retval = TRUE;
goto out_0;
}
if (!_dbus_string_init (&context, _DBUS_INT_MAX))
goto out_0;
if (!_dbus_string_copy_len (data, 0, i,
&context, 0))
goto out_1;
_dbus_string_skip_blank (data, i, &i);
if (!_dbus_string_find_blank (data, i, &j))
{
if (_dbus_string_append (&auth->outgoing,
"ERROR \"Server did not send context/ID/challenge properly\"\r\n"))
retval = TRUE;
goto out_1;
}
if (!_dbus_string_init (&cookie_id_str, _DBUS_INT_MAX))
goto out_1;
if (!_dbus_string_copy_len (data, i, j - i,
&cookie_id_str, 0))
goto out_2;
if (!_dbus_string_init (&server_challenge, _DBUS_INT_MAX))
goto out_2;
i = j;
_dbus_string_skip_blank (data, i, &i);
j = _dbus_string_get_length (data);
if (!_dbus_string_copy_len (data, i, j - i,
&server_challenge, 0))
goto out_3;
if (!_dbus_keyring_validate_context (&context))
{
if (_dbus_string_append (&auth->outgoing,
"ERROR \"Server sent invalid cookie context\"\r\n"))
retval = TRUE;
goto out_3;
}
if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
{
if (_dbus_string_append (&auth->outgoing,
"ERROR \"Could not parse cookie ID as an integer\"\r\n"))
retval = TRUE;
goto out_3;
}
if (_dbus_string_get_length (&server_challenge) == 0)
{
if (_dbus_string_append (&auth->outgoing,
"ERROR \"Empty server challenge string\"\r\n"))
retval = TRUE;
goto out_3;
}
if (auth->keyring == NULL)
{
DBusError error;
dbus_error_init (&error);
auth->keyring = _dbus_keyring_new_homedir (NULL,
&context,
&error);
if (auth->keyring == NULL)
{
if (dbus_error_has_name (&error,
DBUS_ERROR_NO_MEMORY))
{
dbus_error_free (&error);
goto out_3;
}
else
{
_dbus_assert (dbus_error_is_set (&error));
_dbus_verbose ("Error loading keyring: %s\n",
error.message);
if (_dbus_string_append (&auth->outgoing,
"ERROR \"Could not load cookie file\"\r\n"))
retval = TRUE; /* retval is only about mem */
dbus_error_free (&error);
goto out_3;
}
}
else
{
_dbus_assert (!dbus_error_is_set (&error));
}
}
_dbus_assert (auth->keyring != NULL);
if (!_dbus_string_init (&tmp, _DBUS_INT_MAX))
goto out_3;
if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
goto out_4;
if (!_dbus_string_init (&client_challenge, _DBUS_INT_MAX))
goto out_4;
if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
goto out_5;
if (!_dbus_string_init (&correct_hash, _DBUS_INT_MAX))
goto out_6;
if (!sha1_compute_hash (auth, val,
&server_challenge,
&client_challenge,
&correct_hash))
goto out_6;
if (_dbus_string_get_length (&correct_hash) == 0)
{
/* couldn't find the cookie ID or something */
if (_dbus_string_append (&auth->outgoing,
"ERROR \"Don't have the requested cookie ID\"\r\n"))
retval = TRUE;
goto out_6;
}
_dbus_string_set_length (&tmp, 0);
if (!_dbus_string_copy (&client_challenge, 0, &tmp,
_dbus_string_get_length (&tmp)))
goto out_6;
if (!_dbus_string_append (&tmp, " "))
goto out_6;
if (!_dbus_string_copy (&correct_hash, 0, &tmp,
_dbus_string_get_length (&tmp)))
goto out_6;
old_len = _dbus_string_get_length (&auth->outgoing);
if (!_dbus_string_append (&auth->outgoing, "DATA "))
goto out_6;
if (!_dbus_string_base64_encode (&tmp, 0,
&auth->outgoing,
_dbus_string_get_length (&auth->outgoing)))
{
_dbus_string_set_length (&auth->outgoing, old_len);
goto out_6;
}
if (!_dbus_string_append (&auth->outgoing, "\r\n"))
{
_dbus_string_set_length (&auth->outgoing, old_len);
goto out_6;
}
retval = TRUE;
out_6:
_dbus_string_zero (&correct_hash);
_dbus_string_free (&correct_hash);
out_5:
_dbus_string_free (&client_challenge);
out_4:
_dbus_string_zero (&tmp);
_dbus_string_free (&tmp);
out_3:
_dbus_string_free (&server_challenge);
out_2:
_dbus_string_free (&cookie_id_str);
out_1:
_dbus_string_free (&context);
out_0:
return retval;
}
static void
handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
{
auth->cookie_id = -1;
_dbus_string_set_length (&auth->challenge, 0);
}
static dbus_bool_t
handle_server_data_external_mech (DBusAuth *auth,
const DBusString *data)
{
DBusCredentials desired_identity;
if (auth->credentials.uid < 0)
{
_dbus_verbose ("no credentials, mechanism EXTERNAL can't authenticate\n");
@ -418,9 +993,9 @@ handle_server_data_external_mech (DBusAuth *auth,
return FALSE;
}
desired_identity.pid = -1;
desired_identity.uid = -1;
desired_identity.gid = -1;
auth->desired_identity.pid = -1;
auth->desired_identity.uid = -1;
auth->desired_identity.gid = -1;
/* If auth->identity is still empty here, then client
* responded with an empty string after we poked it for
@ -429,37 +1004,37 @@ handle_server_data_external_mech (DBusAuth *auth,
*/
if (_dbus_string_get_length (&auth->identity) == 0)
{
desired_identity.uid = auth->credentials.uid;
auth->desired_identity.uid = auth->credentials.uid;
}
else
{
if (!_dbus_credentials_from_uid_string (&auth->identity,
&desired_identity))
&auth->desired_identity))
{
_dbus_verbose ("could not get credentials from uid string\n");
return send_rejected (auth);
}
}
if (desired_identity.uid < 0)
if (auth->desired_identity.uid < 0)
{
_dbus_verbose ("desired UID %d is no good\n", desired_identity.uid);
_dbus_verbose ("desired UID %d is no good\n", auth->desired_identity.uid);
return send_rejected (auth);
}
if (_dbus_credentials_match (&desired_identity,
if (_dbus_credentials_match (&auth->desired_identity,
&auth->credentials))
{
/* client has authenticated */
_dbus_verbose ("authenticated client with UID %d matching socket credentials UID %d\n",
desired_identity.uid,
auth->credentials.uid);
/* client has authenticated */
if (!_dbus_string_append (&auth->outgoing,
"OK\r\n"))
return FALSE;
auth->authorized_identity.uid = desired_identity.uid;
_dbus_verbose ("authenticated client with UID %d matching socket credentials UID %d\n",
auth->desired_identity.uid,
auth->credentials.uid);
auth->authorized_identity.uid = auth->desired_identity.uid;
auth->authenticated_pending_begin = TRUE;
@ -469,7 +1044,7 @@ handle_server_data_external_mech (DBusAuth *auth,
{
_dbus_verbose ("credentials uid=%d gid=%d do not allow uid=%d gid=%d\n",
auth->credentials.uid, auth->credentials.gid,
desired_identity.uid, desired_identity.gid);
auth->desired_identity.uid, auth->desired_identity.gid);
return send_rejected (auth);
}
}
@ -544,17 +1119,14 @@ all_mechanisms[] = {
handle_client_data_external_mech,
NULL, NULL,
handle_client_shutdown_external_mech },
/* Obviously this has to die for production use */
{ "DBUS_STUPID_TEST_MECH",
handle_server_data_stupid_test_mech,
handle_encode_stupid_test_mech,
handle_decode_stupid_test_mech,
handle_server_shutdown_stupid_test_mech,
NULL,
handle_client_data_stupid_test_mech,
handle_encode_stupid_test_mech,
handle_decode_stupid_test_mech,
handle_client_shutdown_stupid_test_mech },
{ "DBUS_COOKIE_SHA1",
handle_server_data_cookie_sha1_mech,
NULL, NULL,
handle_server_shutdown_cookie_sha1_mech,
handle_client_initial_response_cookie_sha1_mech,
handle_client_data_cookie_sha1_mech,
NULL, NULL,
handle_client_shutdown_cookie_sha1_mech },
{ NULL, NULL }
};
@ -762,6 +1334,16 @@ process_data_server (DBusAuth *auth,
_dbus_string_free (&decoded);
return FALSE;
}
#ifdef DBUS_ENABLE_VERBOSE_MODE
if (_dbus_string_validate_ascii (&decoded, 0,
_dbus_string_get_length (&decoded)))
{
const char *s;
_dbus_string_get_const_data (&decoded, &s);
_dbus_verbose ("data: '%s'\n", s);
}
#endif
if (!(* auth->mech->server_data_func) (auth, &decoded))
{
@ -988,7 +1570,6 @@ process_ok (DBusAuth *auth,
return TRUE;
}
static dbus_bool_t
process_data_client (DBusAuth *auth,
const DBusString *command,
@ -1006,6 +1587,16 @@ process_data_client (DBusAuth *auth,
_dbus_string_free (&decoded);
return FALSE;
}
#ifdef DBUS_ENABLE_VERBOSE_MODE
if (_dbus_string_validate_ascii (&decoded, 0,
_dbus_string_get_length (&decoded)))
{
const char *s;
_dbus_string_get_const_data (&decoded, &s);
_dbus_verbose ("data: '%s'\n", s);
}
#endif
if (!(* auth->mech->client_data_func) (auth, &decoded))
{
@ -1268,6 +1859,9 @@ _dbus_auth_unref (DBusAuth *auth)
_dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
}
if (auth->keyring)
_dbus_keyring_unref (auth->keyring);
_dbus_string_free (&auth->identity);
_dbus_string_free (&auth->incoming);
_dbus_string_free (&auth->outgoing);
@ -1383,6 +1977,12 @@ void
_dbus_auth_bytes_sent (DBusAuth *auth,
int bytes_sent)
{
{
const char *s;
_dbus_string_get_const_data (&auth->outgoing, &s);
_dbus_verbose ("Sent %d bytes of: %s\n", bytes_sent, s);
}
_dbus_string_delete (&auth->outgoing,
0, bytes_sent);
@ -1607,6 +2207,22 @@ _dbus_auth_get_identity (DBusAuth *auth,
}
}
/**
* Sets the "authentication context" which scopes cookies
* with the DBUS_COOKIE_SHA1 auth mechanism for example.
*
* @param auth the auth conversation
* @param context the context
* @returns #FALSE if no memory
*/
dbus_bool_t
_dbus_auth_set_context (DBusAuth *auth,
const DBusString *context)
{
return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
&auth->context, 0, _dbus_string_get_length (context));
}
/** @} */
#ifdef DBUS_BUILD_TESTS

View file

@ -68,6 +68,8 @@ void _dbus_auth_set_credentials (DBusAuth *auth,
void _dbus_auth_get_identity (DBusAuth *auth,
DBusCredentials *credentials);
dbus_bool_t _dbus_auth_set_context (DBusAuth *auth,
const DBusString *context);
DBUS_END_DECLS;

View file

@ -1367,9 +1367,16 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection *connectio
void
dbus_connection_flush (DBusConnection *connection)
{
/* We have to specify DBUS_ITERATION_DO_READING here
* because otherwise we could have two apps deadlock
* if they are both doing a flush(), and the kernel
* buffers fill up.
*/
dbus_mutex_lock (connection->mutex);
while (connection->n_outgoing > 0)
_dbus_connection_do_iteration (connection,
DBUS_ITERATION_DO_READING |
DBUS_ITERATION_DO_WRITING |
DBUS_ITERATION_BLOCK,
-1);

View file

@ -200,6 +200,8 @@ dbus_set_error_const (DBusError *error,
/* it's a bug to pile up errors */
_dbus_assert (error->name == NULL);
_dbus_assert (error->message == NULL);
_dbus_assert (name != NULL);
_dbus_assert (message != NULL);
real = (DBusRealError *)error;
@ -208,6 +210,48 @@ dbus_set_error_const (DBusError *error,
real->const_message = TRUE;
}
/**
* Checks whether the error is set and has the given
* name.
* @param error the error
* @param name the name
* @returns #TRUE if the given named error occurred
*/
dbus_bool_t
dbus_error_has_name (const DBusError *error,
const char *name)
{
_dbus_assert (error != NULL);
_dbus_assert (name != NULL);
_dbus_assert ((error->name != NULL && error->message != NULL) ||
(error->name == NULL && error->message == NULL));
if (error->name != NULL)
{
DBusString str1, str2;
_dbus_string_init_const (&str1, error->name);
_dbus_string_init_const (&str2, name);
return _dbus_string_equal (&str1, &str2);
}
else
return FALSE;
}
/**
* Checks whether an error occurred (the error is set).
*
* @param error the error object
* @returns #TRUE if an error occurred
*/
dbus_bool_t
dbus_error_is_set (const DBusError *error)
{
_dbus_assert (error != NULL);
_dbus_assert ((error->name != NULL && error->message != NULL) ||
(error->name == NULL && error->message == NULL));
return error->name != NULL;
}
/**
* Assigns an error name and message to a DBusError.
* Does nothing if error is #NULL.
@ -240,6 +284,8 @@ dbus_set_error (DBusError *error,
/* it's a bug to pile up errors */
_dbus_assert (error->name == NULL);
_dbus_assert (error->message == NULL);
_dbus_assert (name != NULL);
_dbus_assert (format != NULL);
va_start (args, format);
/* Measure the message length */

View file

@ -81,16 +81,20 @@ typedef enum
DBUS_RESULT_FILE_NOT_FOUND /**< File doesn't exist */
} DBusResultCode;
void dbus_error_init (DBusError *error);
void dbus_error_free (DBusError *error);
void dbus_set_error (DBusError *error,
const char *name,
const char *message,
...);
void dbus_set_error_const (DBusError *error,
const char *name,
const char *message);
void dbus_error_init (DBusError *error);
void dbus_error_free (DBusError *error);
void dbus_set_error (DBusError *error,
const char *name,
const char *message,
...);
void dbus_set_error_const (DBusError *error,
const char *name,
const char *message);
dbus_bool_t dbus_error_has_name (const DBusError *error,
const char *name);
dbus_bool_t dbus_error_is_set (const DBusError *error);
void dbus_set_result (DBusResultCode *code_address,
DBusResultCode code);
const char* dbus_result_to_string (DBusResultCode code);

View file

@ -92,6 +92,7 @@ typedef struct
struct DBusKeyring
{
int refcount; /**< Reference count */
DBusString username; /**< Username keyring is for */
DBusString directory; /**< Directory the below two items are inside */
DBusString filename; /**< Keyring filename */
DBusString filename_lock; /**< Name of lockfile */
@ -117,12 +118,17 @@ _dbus_keyring_new (void)
if (!_dbus_string_init (&keyring->filename_lock, _DBUS_INT_MAX))
goto out_3;
if (!_dbus_string_init (&keyring->username, _DBUS_INT_MAX))
goto out_4;
keyring->refcount = 1;
keyring->keys = NULL;
keyring->n_keys = 0;
return keyring;
out_4:
_dbus_string_free (&keyring->username);
out_3:
_dbus_string_free (&keyring->filename);
out_2:
@ -614,6 +620,7 @@ _dbus_keyring_reload (DBusKeyring *keyring,
i = 0;
while (i < n_keys)
{
_dbus_string_zero (&keys[i].secret);
_dbus_string_free (&keys[i].secret);
++i;
}
@ -659,6 +666,7 @@ _dbus_keyring_unref (DBusKeyring *keyring)
if (keyring->refcount == 0)
{
_dbus_string_free (&keyring->username);
_dbus_string_free (&keyring->filename);
_dbus_string_free (&keyring->filename_lock);
_dbus_string_free (&keyring->directory);
@ -715,6 +723,8 @@ _dbus_keyring_new_homedir (const DBusString *username,
goto failed;
}
_dbus_assert (username != NULL);
keyring = _dbus_keyring_new ();
if (keyring == NULL)
goto failed;
@ -728,7 +738,11 @@ _dbus_keyring_new_homedir (const DBusString *username,
"Invalid context in keyring creation");
goto failed;
}
if (!_dbus_string_copy (username, 0,
&keyring->username, 0))
goto failed;
if (!_dbus_string_copy (&homedir, 0,
&keyring->directory, 0))
goto failed;
@ -795,6 +809,9 @@ _dbus_keyring_new_homedir (const DBusString *username,
* in filenames are not allowed (contexts can't
* start with a dot or contain dir separators).
*
* @todo this is the most inefficient implementation
* imaginable.
*
* @param context the context
* @returns #TRUE if valid
*/
@ -836,6 +853,25 @@ _dbus_keyring_validate_context (const DBusString *context)
return FALSE;
}
/* no spaces/tabs, those are used for separators in the protocol */
if (_dbus_string_find_blank (context, 0, NULL))
{
_dbus_verbose ("context contains a blank\n");
return FALSE;
}
if (_dbus_string_find (context, 0, "\n", NULL))
{
_dbus_verbose ("context contains a newline\n");
return FALSE;
}
if (_dbus_string_find (context, 0, "\r", NULL))
{
_dbus_verbose ("context contains a carriage return\n");
return FALSE;
}
return TRUE;
}
@ -904,6 +940,51 @@ _dbus_keyring_get_best_key (DBusKeyring *keyring,
}
}
/**
* Checks whether the keyring is for the given username.
*
* @param keyring the keyring
* @param username the username to check
*
* @returns #TRUE if the keyring belongs to the given user
*/
dbus_bool_t
_dbus_keyring_is_for_user (DBusKeyring *keyring,
const DBusString *username)
{
return _dbus_string_equal (&keyring->username,
username);
}
/**
* Gets the hex-encoded secret key for the given ID.
* Returns #FALSE if not enough memory. Returns #TRUE
* but empty key on any other error such as unknown
* key ID.
*
* @param keyring the keyring
* @param key_id the key ID
* @param hex_key string to append hex-encoded key to
* @returns #TRUE if we had enough memory
*/
dbus_bool_t
_dbus_keyring_get_hex_key (DBusKeyring *keyring,
int key_id,
DBusString *hex_key)
{
DBusKey *key;
key = find_key_by_id (keyring->keys,
keyring->n_keys,
key_id);
if (key == NULL)
return TRUE; /* had enough memory, so TRUE */
return _dbus_string_hex_encode (&key->secret, 0,
hex_key,
_dbus_string_get_length (hex_key));
}
/** @} */ /* end of exposed API */
#ifdef DBUS_BUILD_TESTS
@ -946,6 +1027,8 @@ _dbus_keyring_test (void)
_dbus_assert (!_dbus_keyring_validate_context (&context));
_dbus_string_init_const (&context, "foo\x7f");
_dbus_assert (_dbus_keyring_validate_context (&context));
_dbus_string_init_const (&context, "foo bar");
_dbus_assert (!_dbus_keyring_validate_context (&context));
if (!_dbus_string_init (&context, _DBUS_INT_MAX))
_dbus_assert_not_reached ("no memory");

View file

@ -39,16 +39,11 @@ void _dbus_keyring_unref (DBusKeyring *keyring);
dbus_bool_t _dbus_keyring_validate_context (const DBusString *context);
int _dbus_keyring_get_best_key (DBusKeyring *keyring,
DBusError *error);
dbus_bool_t _dbus_keyring_create_challenge (DBusString *challenge);
dbus_bool_t _dbus_keyring_compute_response (DBusKeyring *keyring,
dbus_bool_t _dbus_keyring_is_for_user (DBusKeyring *keyring,
const DBusString *username);
dbus_bool_t _dbus_keyring_get_hex_key (DBusKeyring *keyring,
int key_id,
const DBusString *challenge,
DBusString *response);
dbus_bool_t _dbus_keyring_check_response (DBusKeyring *keyring,
int key_id,
const DBusString *challenge,
const DBusString *response);
DBusString *hex_key);
DBUS_END_DECLS;

View file

@ -148,7 +148,7 @@ clear_header_padding (DBusMessage *message)
_dbus_string_shorten (&message->header,
message->header_padding);
message->header_padding = 0;
}
}
static dbus_bool_t
append_header_padding (DBusMessage *message)
@ -2653,7 +2653,9 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
int i;
int next_arg;
#if 0
_dbus_verbose_bytes_of_string (&loader->data, 0, header_len);
#endif
if (!decode_header_data (&loader->data, header_len, byte_order,
fields, &header_padding))
{

View file

@ -1107,14 +1107,17 @@ get_user_info (const DBusString *username,
DBusString *username_out)
{
const char *username_c_str;
credentials->pid = -1;
credentials->uid = -1;
credentials->gid = -1;
/* exactly one of username/uid provided */
_dbus_assert (username != NULL || uid >= 0);
_dbus_assert (username == NULL || uid < 0);
if (credentials)
{
credentials->pid = -1;
credentials->uid = -1;
credentials->gid = -1;
}
if (username != NULL)
_dbus_string_get_const_data (username, &username_c_str);

View file

@ -66,11 +66,13 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
printf ("%s: running keyring tests\n", "dbus-test");
if (!_dbus_keyring_test ())
die ("keyring");
#if 0
printf ("%s: running md5 tests\n", "dbus-test");
if (!_dbus_md5_test ())
die ("md5");
#endif
printf ("%s: running SHA-1 tests\n", "dbus-test");
if (!_dbus_sha_test (test_data_dir))
die ("SHA-1");

View file

@ -476,7 +476,6 @@
<para>
The credentials sent along with the nul byte may be used with the
SASL mechanism EXTERNAL.
</para>
</sect2>
<sect2 id="auth-command-auth">
@ -683,6 +682,150 @@
</figure>
</para>
</sect2>
<sect2 id="auth-mechanisms">
<title>Authentication mechanisms</title>
<para>
This section describes some new authentication mechanisms.
D-BUS also allows any standard SASL mechanism of course.
</para>
<sect3 id="auth-mechanisms-sha">
<title>DBUS_COOKIE_SHA1</title>
<para>
The DBUS_COOKIE_SHA1 mechanism is designed to establish that a client
has the ability to read a private file owned by the user being
authenticated. If the client can prove that it has access to a secret
cookie stored in this file, then the client is authenticated.
Thus the security of DBUS_COOKIE_SHA1 depends on a secure home
directory.
</para>
<para>
Authentication proceeds as follows:
<itemizedlist>
<listitem>
<para>
The client sends the username it would like to authenticate
as.
</para>
</listitem>
<listitem>
<para>
The server sends the name of its "cookie context" (see below); a
space character; the integer ID of the secret cookie the client
must demonstrate knowledge of; a space character; then a
hex-encoded randomly-generated challenge string.
</para>
</listitem>
<listitem>
<para>
The client locates the cookie, and generates its own hex-encoded
randomly-generated challenge string. The client then
concatentates the server's hex-encoded challenge, a ":"
character, its own hex-encoded challenge, another ":" character,
and the hex-encoded cookie. It computes the SHA-1 hash of this
composite string. It sends back to the server the client's
hex-encoded challenge string, a space character, and the SHA-1
hash.
</para>
</listitem>
<listitem>
<para>
The server generates the same concatenated string used by the
client and computes its SHA-1 hash. It compares the hash with
the hash received from the client; if the two hashes match, the
client is authenticated.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Each server has a "cookie context," which is a name that identifies a
set of cookies that apply to that server. A sample context might be
"org_freedesktop_session_bus". Context names must be valid ASCII,
nonzero length, and may not contain the characters slash ("/"),
backslash ("\"), space (" "), newline ("\n"), carriage return ("\r"),
tab ("\t"), or period ("."). There is a default context,
"org_freedesktop_global" that's used by servers that do not specify
otherwise.
</para>
<para>
Cookies are stored in a user's home directory, in the directory
<filename>~/.dbus-keyrings/</filename>. This directory must
not be readable or writable by other users. If it is,
clients and servers must ignore it. The directory
contains cookie files named after the cookie context.
</para>
<para>
A cookie file contains one cookie per line. Each line
has three space-separated fields:
<itemizedlist>
<listitem>
<para>
The cookie ID number, which must be a non-negative integer and
may not be used twice in the same file.
</para>
</listitem>
<listitem>
<para>
The cookie's creation time, in UNIX seconds-since-the-epoch
format.
</para>
</listitem>
<listitem>
<para>
The cookie itself, a hex-encoded random block of bytes.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Only server processes modify the cookie file.
They must do so with this procedure:
<itemizedlist>
<listitem>
<para>
Create a lockfile name by appending ".lock" to the name of the
cookie file. The server should attempt to create this file
using <literal>O_CREAT | O_EXCL</literal>. If file creation
fails, the lock fails. Servers should retry for a reasonable
period of time, then they may choose to delete an existing lock
to keep users from having to manually delete a stale
lock. <footnote><para>Lockfiles are used instead of real file
locking <literal>fcntl()</literal> because real locking
implementations are still flaky on network
filesystems.</para></footnote>
</para>
</listitem>
<listitem>
<para>
Once the lockfile has been created, the server loads the cookie
file. It should then delete any cookies that are old (the
timeout can be fairly short), or more than a reasonable
time in the future (so that cookies never accidentally
become permanent, if the clock was set far into the future
at some point). If no recent keys remain, the
server may generate a new key.
</para>
</listitem>
<listitem>
<para>
The pruned and possibly added-to cookie file
must be resaved atomically (using a temporary
file which is rename()'d).
</para>
</listitem>
<listitem>
<para>
The lock must be dropped by deleting the lockfile.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Clients need not lock the file in order to load it,
because servers are required to save the file atomically.
</para>
</sect3>
</sect2>
</sect1>
<sect1 id="addresses">
<title>Server Addresses</title>

View file

@ -2,7 +2,7 @@
SERVER
NO_CREDENTIALS
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND REJECTED
EXPECT_STATE WAITING_FOR_INPUT

View file

@ -2,7 +2,7 @@
SERVER
ROOT_CREDENTIALS
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND OK
EXPECT_STATE WAITING_FOR_INPUT
SEND 'BEGIN'

View file

@ -2,7 +2,7 @@
SERVER
SILLY_CREDENTIALS
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND REJECTED
EXPECT_STATE WAITING_FOR_INPUT

View file

@ -1,7 +1,7 @@
## this tests a successful auth of type EXTERNAL
SERVER
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND OK
EXPECT_STATE WAITING_FOR_INPUT
SEND 'BEGIN'

View file

@ -1,7 +1,7 @@
## this tests that we have the expected extra bytes at the end
SERVER
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND OK
EXPECT_STATE WAITING_FOR_INPUT
SEND 'BEGIN\r\nHello'

View file

@ -4,30 +4,30 @@ SERVER
NO_CREDENTIALS
# 1
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND REJECTED
EXPECT_STATE WAITING_FOR_INPUT
# 2
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND REJECTED
EXPECT_STATE WAITING_FOR_INPUT
# 3
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND REJECTED
EXPECT_STATE WAITING_FOR_INPUT
# 4
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND REJECTED
EXPECT_STATE WAITING_FOR_INPUT
# 5
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_COMMAND REJECTED
EXPECT_STATE WAITING_FOR_INPUT
# 6
SEND 'AUTH EXTERNAL USERNAME_BASE64'
SEND 'AUTH EXTERNAL USERID_BASE64'
EXPECT_STATE NEED_DISCONNECT

View file

@ -5,17 +5,18 @@ CLIENT
## Will try EXTERNAL by default first without first calling AUTH alone.
EXPECT_COMMAND AUTH
SEND 'REJECTED EXTERNAL DBUS_STUPID_TEST_MECH'
SEND 'REJECTED EXTERNAL DBUS_COOKIE_SHA1 DBUS_TEST_NONEXISTENT_MECH'
## Will try EXTERNAL again.
EXPECT_COMMAND AUTH
SEND 'REJECTED EXTERNAL DBUS_STUPID_TEST_MECH'
SEND 'REJECTED EXTERNAL DBUS_COOKIE_SHA1 DBUS_TEST_NONEXISTENT_MECH'
## And this time we get DBUS_STUPID_TEST_MECH.
## And this time we get DBUS_COOKIE_SHA1
EXPECT_COMMAND AUTH
## of course real DBUS_COOKIE_SHA1 would not send this here...
SEND 'OK'
EXPECT_COMMAND BEGIN
EXPECT_STATE AUTHENTICATED
EXPECT_STATE AUTHENTICATED