mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-05-27 10:28:14 +02:00
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:
parent
6bea42d2b8
commit
7e050c8871
21 changed files with 1115 additions and 147 deletions
23
ChangeLog
23
ChangeLog
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
810
dbus/dbus-auth.c
810
dbus/dbus-auth.c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue