#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 */
* @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
*/
/**
* 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
unsigned int authenticated_pending_begin : 1; /**< Authenticated once we get BEGIN */
unsigned int already_got_mechanisms : 1; /**< Client already got mech list */
unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */
+ unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */
};
typedef struct
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
* overlong buffers in _dbus_auth_do_work().
*/
- if (!_dbus_string_init (&auth->incoming, _DBUS_INT_MAX))
- {
- dbus_free (auth);
- return NULL;
- }
+ if (!_dbus_string_init (&auth->incoming))
+ goto enomem_0;
- if (!_dbus_string_init (&auth->outgoing, _DBUS_INT_MAX))
- {
- _dbus_string_free (&auth->incoming);
- dbus_free (auth);
- return NULL;
- }
-
- if (!_dbus_string_init (&auth->identity, _DBUS_INT_MAX))
- {
- _dbus_string_free (&auth->incoming);
- _dbus_string_free (&auth->outgoing);
- dbus_free (auth);
- return NULL;
- }
+ if (!_dbus_string_init (&auth->outgoing))
+ goto enomem_1;
+
+ if (!_dbus_string_init (&auth->identity))
+ goto enomem_2;
+
+ if (!_dbus_string_init (&auth->context))
+ goto enomem_3;
+
+ if (!_dbus_string_init (&auth->challenge))
+ 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->outgoing);
+ enomem_1:
+ _dbus_string_free (&auth->incoming);
+ enomem_0:
+ dbus_free (auth);
+ return NULL;
}
static void
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)
{
}
}
+/* 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))
return FALSE;
- auth->authenticated_pending_begin = TRUE;
+ 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))
+ 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. This is the number of bytes in the random
+ * challenge.
+ */
+#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))
+ return FALSE;
+
+ if (!_dbus_string_init (&tmp2))
+ {
+ _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_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_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))
+ goto out_0;
+
+ if (!_dbus_string_init (&client_hash))
+ 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))
+ 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))
+ 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))
+ 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))
+ 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_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))
+ goto out_3;
+
+ if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
+ goto out_4;
+
+ if (!_dbus_string_init (&client_challenge))
+ goto out_4;
+
+ if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
+ goto out_5;
+
+ if (!_dbus_string_init (&correct_hash))
+ 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");
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
*/
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;
{
_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);
}
}
*/
DBusString plaintext;
- if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&plaintext))
return FALSE;
if (!_dbus_string_append_our_uid (&plaintext))
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 }
};
DBusAuthServer *server_auth;
int i;
- if (!_dbus_string_init (&command, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&command))
return FALSE;
if (!_dbus_string_append (&command,
_dbus_assert (DBUS_AUTH_IS_SERVER (auth));
server_auth = DBUS_AUTH_SERVER (auth);
server_auth->failures += 1;
+
+ _dbus_string_free (&command);
return TRUE;
_dbus_string_find_blank (args, 0, &i);
- if (!_dbus_string_init (&mech, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&mech))
return FALSE;
- if (!_dbus_string_init (&base64_response, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&base64_response))
{
_dbus_string_free (&mech);
return FALSE;
}
-
- if (!_dbus_string_init (&decoded_response, _DBUS_INT_MAX))
+
+ if (!_dbus_string_init (&decoded_response))
{
_dbus_string_free (&mech);
_dbus_string_free (&base64_response);
return FALSE;
}
-
+
if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
goto failed;
if (!_dbus_string_base64_decode (&base64_response, 0,
&decoded_response, 0))
goto failed;
-
+
auth->mech = find_mech (&mech);
if (auth->mech != NULL)
{
{
/* Unsupported mechanism */
if (!send_rejected (auth))
- return FALSE;
+ goto failed;
}
_dbus_string_free (&mech);
{
DBusString decoded;
- if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&decoded))
return FALSE;
if (!_dbus_string_base64_decode (args, 0, &decoded, 0))
_dbus_string_free (&decoded);
return FALSE;
}
+
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ if (_dbus_string_validate_ascii (&decoded, 0,
+ _dbus_string_get_length (&decoded)))
+ _dbus_verbose ("data: '%s'\n", _dbus_string_get_const_data (&decoded));
+#endif
if (!(* auth->mech->server_data_func) (auth, &decoded))
{
if (i > *start)
{
- if (!_dbus_string_copy_len (str, *start, i, word, 0))
+ if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
return FALSE;
*start = i;
DBusString m;
const DBusAuthMechanismHandler *mech;
- if (!_dbus_string_init (&m, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&m))
goto nomem;
if (!get_word (args, &next, &m))
}
else
{
- const char *s;
-
- _dbus_string_get_const_data (&m, &s);
_dbus_verbose ("Server offered mechanism \"%s\" that we don't know how to use\n",
- s);
+ _dbus_string_get_const_data (&m));
}
_dbus_string_free (&m);
mech = DBUS_AUTH_CLIENT (auth)->mechs_to_try->data;
- if (!_dbus_string_init (&auth_command, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&auth_command))
return FALSE;
if (!_dbus_string_append (&auth_command,
return TRUE;
}
-
static dbus_bool_t
process_data_client (DBusAuth *auth,
const DBusString *command,
{
DBusString decoded;
- if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&decoded))
return FALSE;
if (!_dbus_string_base64_decode (args, 0, &decoded, 0))
_dbus_string_free (&decoded);
return FALSE;
}
+
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ if (_dbus_string_validate_ascii (&decoded, 0,
+ _dbus_string_get_length (&decoded)))
+ {
+ _dbus_verbose ("data: '%s'\n",
+ _dbus_string_get_const_data (&decoded));
+ }
+#endif
if (!(* auth->mech->client_data_func) (auth, &decoded))
{
if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
return FALSE;
- if (!_dbus_string_init (&command, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&command))
{
auth->needed_memory = TRUE;
return FALSE;
}
- if (!_dbus_string_init (&args, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&args))
{
+ _dbus_string_free (&command);
auth->needed_memory = TRUE;
return FALSE;
}
goto next_command;
}
- {
- const char *q;
- _dbus_string_get_const_data (&command, &q);
- _dbus_verbose ("got command \"%s\"\n", q);
- }
+ _dbus_verbose ("got command \"%s\"\n", _dbus_string_get_const_data (&command));
_dbus_string_find_blank (&command, 0, &i);
_dbus_string_skip_blank (&command, i, &j);
_dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
}
+ if (auth->keyring)
+ _dbus_keyring_unref (auth->keyring);
+
+ _dbus_string_free (&auth->context);
+ _dbus_string_free (&auth->challenge);
_dbus_string_free (&auth->identity);
_dbus_string_free (&auth->incoming);
_dbus_string_free (&auth->outgoing);
_dbus_auth_bytes_sent (DBusAuth *auth,
int bytes_sent)
{
+ _dbus_verbose ("Sent %d bytes of: %s\n", bytes_sent,
+ _dbus_string_get_const_data (&auth->outgoing));
+
_dbus_string_delete (&auth->outgoing,
0, bytes_sent);
}
/**
- * Stores bytes received from the peer we're conversing with.
+ * Get a buffer to be used for reading bytes from the peer we're conversing
+ * with. Bytes should be appended to this buffer.
*
* @param auth the auth conversation
- * @param str the received bytes.
- * @returns #FALSE if not enough memory to store the bytes or we were already authenticated.
+ * @param buffer return location for buffer to append bytes to
*/
-dbus_bool_t
-_dbus_auth_bytes_received (DBusAuth *auth,
- const DBusString *str)
+void
+_dbus_auth_get_buffer (DBusAuth *auth,
+ DBusString **buffer)
{
_dbus_assert (auth != NULL);
- _dbus_assert (str != NULL);
+ _dbus_assert (!auth->buffer_outstanding);
- if (DBUS_AUTH_IN_END_STATE (auth))
- return FALSE;
+ *buffer = &auth->incoming;
- auth->needed_memory = FALSE;
-
- if (!_dbus_string_copy (str, 0,
- &auth->incoming,
- _dbus_string_get_length (&auth->incoming)))
- {
- auth->needed_memory = TRUE;
- return FALSE;
- }
+ auth->buffer_outstanding = TRUE;
+}
- _dbus_auth_do_work (auth);
-
- return TRUE;
+/**
+ * Returns a buffer with new data read into it.
+ *
+ * @param auth the auth conversation
+ * @param buffer the buffer being returned
+ * @param bytes_read number of new bytes added
+ */
+void
+_dbus_auth_return_buffer (DBusAuth *auth,
+ DBusString *buffer,
+ int bytes_read)
+{
+ _dbus_assert (buffer == &auth->incoming);
+ _dbus_assert (auth->buffer_outstanding);
+
+ auth->buffer_outstanding = FALSE;
}
/**
* succeeded.
*
* @param auth the auth conversation
- * @param str string to append the unused bytes to
- * @returns #FALSE if not enough memory to return the bytes
+ * @param str return location for pointer to string of unused bytes
*/
-dbus_bool_t
-_dbus_auth_get_unused_bytes (DBusAuth *auth,
- DBusString *str)
+void
+_dbus_auth_get_unused_bytes (DBusAuth *auth,
+ const DBusString **str)
{
if (!DBUS_AUTH_IN_END_STATE (auth))
- return FALSE;
-
- if (!_dbus_string_move (&auth->incoming,
- 0, str,
- _dbus_string_get_length (str)))
- return FALSE;
+ return;
- return TRUE;
+ *str = &auth->incoming;
+}
+
+
+/**
+ * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes()
+ * after we've gotten them and successfully moved them elsewhere.
+ *
+ * @param auth the auth conversation
+ */
+void
+_dbus_auth_delete_unused_bytes (DBusAuth *auth)
+{
+ if (!DBUS_AUTH_IN_END_STATE (auth))
+ return;
+
+ _dbus_string_set_length (&auth->incoming, 0);
}
/**
}
}
+/**
+ * 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
DBusString filename;
DBusDirIter *dir;
dbus_bool_t retval;
- DBusResultCode result;
+ DBusError error;
retval = FALSE;
dir = NULL;
- if (!_dbus_string_init (&test_directory, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&test_directory))
_dbus_assert_not_reached ("didn't allocate test_directory\n");
_dbus_string_init_const (&filename, subdir);
_dbus_assert_not_reached ("couldn't allocate full path");
_dbus_string_free (&filename);
- if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&filename))
_dbus_assert_not_reached ("didn't allocate filename string\n");
-
- dir = _dbus_directory_open (&test_directory, &result);
+
+ dbus_error_init (&error);
+ dir = _dbus_directory_open (&test_directory, &error);
if (dir == NULL)
{
- const char *s;
- _dbus_string_get_const_data (&test_directory, &s);
- _dbus_warn ("Could not open %s: %s\n", s,
- dbus_result_to_string (result));
+ _dbus_warn ("Could not open %s: %s\n",
+ _dbus_string_get_const_data (&test_directory),
+ error.message);
+ dbus_error_free (&error);
goto failed;
}
printf ("Testing:\n");
- result = DBUS_RESULT_SUCCESS;
next:
- while (_dbus_directory_get_next_file (dir, &filename, &result))
+ while (_dbus_directory_get_next_file (dir, &filename, &error))
{
DBusString full_path;
- if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&full_path))
_dbus_assert_not_reached ("couldn't init string");
if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
if (!_dbus_string_ends_with_c_str (&filename, ".auth-script"))
{
- const char *filename_c;
- _dbus_string_get_const_data (&filename, &filename_c);
_dbus_verbose ("Skipping non-.auth-script file %s\n",
- filename_c);
+ _dbus_string_get_const_data (&filename));
+ _dbus_string_free (&full_path);
goto next;
}
- {
- const char *s;
- _dbus_string_get_const_data (&filename, &s);
- printf (" %s\n", s);
- }
+ printf (" %s\n", _dbus_string_get_const_data (&filename));
if (!_dbus_auth_script_run (&full_path))
{
_dbus_string_free (&full_path);
}
- if (result != DBUS_RESULT_SUCCESS)
+ if (dbus_error_is_set (&error))
{
- const char *s;
- _dbus_string_get_const_data (&test_directory, &s);
_dbus_warn ("Could not get next file in %s: %s\n",
- s, dbus_result_to_string (result));
+ _dbus_string_get_const_data (&test_directory), error.message);
+ dbus_error_free (&error);
goto failed;
}