summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-03-05 02:01:34 +0000
committerHavoc Pennington <hp@redhat.com>2003-03-05 02:01:34 +0000
commit7e050c88719553d0c74e3dc68caf7bc50ae99590 (patch)
treef7a9abccae6591849e58e71d45dded9aa76512ec
parent6bea42d2b84121152e4e5c719d23ed22901a972a (diff)
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.
-rw-r--r--ChangeLog23
-rw-r--r--dbus/Makefile.am5
-rw-r--r--dbus/dbus-auth-script.c46
-rw-r--r--dbus/dbus-auth.c770
-rw-r--r--dbus/dbus-auth.h2
-rw-r--r--dbus/dbus-connection.c7
-rw-r--r--dbus/dbus-errors.c46
-rw-r--r--dbus/dbus-errors.h24
-rw-r--r--dbus/dbus-keyring.c87
-rw-r--r--dbus/dbus-keyring.h13
-rw-r--r--dbus/dbus-message.c4
-rw-r--r--dbus/dbus-sysdeps.c13
-rw-r--r--dbus/dbus-test.c6
-rw-r--r--doc/dbus-specification.sgml145
-rw-r--r--test/data/auth/external-failed.auth-script2
-rw-r--r--test/data/auth/external-root.auth-script2
-rw-r--r--test/data/auth/external-silly.auth-script2
-rw-r--r--test/data/auth/external-successful.auth-script2
-rw-r--r--test/data/auth/extra-bytes.auth-script2
-rw-r--r--test/data/auth/fail-after-n-attempts.auth-script12
-rw-r--r--test/data/auth/fallback.auth-script9
21 files changed, 1095 insertions, 127 deletions
diff --git a/ChangeLog b/ChangeLog
index c897b38b..ab0abd9a 100644
--- a/ChangeLog
+++ b/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.
diff --git a/dbus/Makefile.am b/dbus/Makefile.am
index b0b001af..dfcfb7d4 100644
--- a/dbus/Makefile.am
+++ b/dbus/Makefile.am
@@ -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.
diff --git a/dbus/dbus-auth-script.c b/dbus/dbus-auth-script.c
index 4dccfe9f..732b4515 100644
--- a/dbus/dbus-auth-script.c
+++ b/dbus/dbus-auth-script.c
@@ -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,24 +363,60 @@ _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 username\n");
+ _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");
+ _dbus_string_free (&to_send);
+ goto out;
+ }
+
+ 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);
_dbus_string_free (&to_send);
diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
index f078136c..516a51ae 100644
--- a/dbus/dbus-auth.c
+++ b/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)
}
}
+/* 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_server_data_stupid_test_mech (DBusAuth *auth,
- const DBusString *data)
+sha1_compute_hash (DBusAuth *auth,
+ int cookie_id,
+ const DBusString *server_challenge,
+ const DBusString *client_challenge,
+ DBusString *hash)
{
- if (!_dbus_string_append (&auth->outgoing,
- "OK\r\n"))
+ DBusString cookie;
+ DBusString to_hash;
+ dbus_bool_t retval;
+
+ _dbus_assert (auth->keyring != NULL);
+
+ retval = FALSE;
+
+ if (!_dbus_string_init (&cookie, _DBUS_INT_MAX))
return FALSE;
- _dbus_credentials_from_current_process (&auth->authorized_identity);
+ if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id,
+ &cookie))
+ goto out_0;
- auth->authenticated_pending_begin = TRUE;
+ if (_dbus_string_get_length (&cookie) == 0)
+ {
+ retval = TRUE;
+ goto out_0;
+ }
+
+ if (!_dbus_string_init (&to_hash, _DBUS_INT_MAX))
+ goto out_0;
- return TRUE;
+ 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;
}
-static void
-handle_server_shutdown_stupid_test_mech (DBusAuth *auth)
+/* 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_client_data_stupid_test_mech (DBusAuth *auth,
- const DBusString *data)
+sha1_handle_second_client_response (DBusAuth *auth,
+ const DBusString *data)
{
+ /* 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 void
-handle_client_shutdown_stupid_test_mech (DBusAuth *auth)
+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);
}
-/* the stupid test mech is a base64-encoded string;
- * all the inefficiency, none of the security!
- */
static dbus_bool_t
-handle_encode_stupid_test_mech (DBusAuth *auth,
- const DBusString *plaintext,
- DBusString *encoded)
+handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth,
+ DBusString *response)
{
- if (!_dbus_string_base64_encode (plaintext, 0, encoded,
- _dbus_string_get_length (encoded)))
- return FALSE;
+ 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;
- return 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_decode_stupid_test_mech (DBusAuth *auth,
- const DBusString *encoded,
- DBusString *plaintext)
+handle_client_data_cookie_sha1_mech (DBusAuth *auth,
+ const DBusString *data)
{
- if (!_dbus_string_base64_decode (encoded, 0, plaintext,
- _dbus_string_get_length (plaintext)))
- return FALSE;
+ /* 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;
- return TRUE;
+ 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
diff --git a/dbus/dbus-auth.h b/dbus/dbus-auth.h
index 7346f99b..0339a4f8 100644
--- a/dbus/dbus-auth.h
+++ b/dbus/dbus-auth.h
@@ -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;
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index 134736d2..3611b871 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -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);
diff --git a/dbus/dbus-errors.c b/dbus/dbus-errors.c
index 3aca9f10..e57d3538 100644
--- a/dbus/dbus-errors.c
+++ b/dbus/dbus-errors.c
@@ -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;
@@ -209,6 +211,48 @@ dbus_set_error_const (DBusError *error,
}
/**
+ * 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 */
diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h
index 1b1a880c..e6b88465 100644
--- a/dbus/dbus-errors.h
+++ b/dbus/dbus-errors.h
@@ -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);
diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c
index d4aae2fb..c5c6a0b5 100644
--- a/dbus/dbus-keyring.c
+++ b/dbus/dbus-keyring.c
@@ -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");
diff --git a/dbus/dbus-keyring.h b/dbus/dbus-keyring.h
index 28826aed..2a450ec8 100644
--- a/dbus/dbus-keyring.h
+++ b/dbus/dbus-keyring.h
@@ -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;
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index e0823112..db1b94bf 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -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))
{
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index 2310b000..d096ce3e 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -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);
diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c
index 29ad855d..9da24ba3 100644
--- a/dbus/dbus-test.c
+++ b/dbus/dbus-test.c
@@ -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");
diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml
index 48cc086d..0845d806 100644
--- a/doc/dbus-specification.sgml
+++ b/doc/dbus-specification.sgml
@@ -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>
diff --git a/test/data/auth/external-failed.auth-script b/test/data/auth/external-failed.auth-script
index f5723521..8f0d1aa9 100644
--- a/test/data/auth/external-failed.auth-script
+++ b/test/data/auth/external-failed.auth-script
@@ -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
diff --git a/test/data/auth/external-root.auth-script b/test/data/auth/external-root.auth-script
index 720b7e51..c126067c 100644
--- a/test/data/auth/external-root.auth-script
+++ b/test/data/auth/external-root.auth-script
@@ -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'
diff --git a/test/data/auth/external-silly.auth-script b/test/data/auth/external-silly.auth-script
index 3e12c153..cbfef8fd 100644
--- a/test/data/auth/external-silly.auth-script
+++ b/test/data/auth/external-silly.auth-script
@@ -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
diff --git a/test/data/auth/external-successful.auth-script b/test/data/auth/external-successful.auth-script
index 1b380802..02ecdc08 100644
--- a/test/data/auth/external-successful.auth-script
+++ b/test/data/auth/external-successful.auth-script
@@ -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'
diff --git a/test/data/auth/extra-bytes.auth-script b/test/data/auth/extra-bytes.auth-script
index df8df52b..0bd705dc 100644
--- a/test/data/auth/extra-bytes.auth-script
+++ b/test/data/auth/extra-bytes.auth-script
@@ -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'
diff --git a/test/data/auth/fail-after-n-attempts.auth-script b/test/data/auth/fail-after-n-attempts.auth-script
index 75bd3801..ae3b907a 100644
--- a/test/data/auth/fail-after-n-attempts.auth-script
+++ b/test/data/auth/fail-after-n-attempts.auth-script
@@ -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
diff --git a/test/data/auth/fallback.auth-script b/test/data/auth/fallback.auth-script
index 1b8c40f5..ebe7ae28 100644
--- a/test/data/auth/fallback.auth-script
+++ b/test/data/auth/fallback.auth-script
@@ -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