Commit a789b7b3 authored by Havoc Pennington's avatar Havoc Pennington
Browse files

2007-06-09 Havoc Pennington <hp@redhat.com>

	* dbus/dbus-string.c (_dbus_string_pop_line): fix this not to
	think an empty line is the end of the file.
	Also, fix some whitespace.

	* dbus/dbus-string-util.c: add more tests for
	_dbus_string_pop_line() revealing that it thinks an empty line is
	the end of the file, which broke dbus-auth-script.c so
	it didn't really run the scripts

	* dbus/dbus-auth.c: add ANONYMOUS mechanism

	* dbus/dbus-auth-script.c (_dbus_auth_script_run): fix to detect
	an empty/no-op auth script; add commands to check that we have or
	don't have the expected credentials
parent 7be5fd95
2007-06-09 Havoc Pennington <hp@redhat.com>
* dbus/dbus-string.c (_dbus_string_pop_line): fix this not to
think an empty line is the end of the file.
Also, fix some whitespace.
* dbus/dbus-string-util.c: add more tests for
_dbus_string_pop_line() revealing that it thinks an empty line is
the end of the file, which broke dbus-auth-script.c so
it didn't really run the scripts
* dbus/dbus-auth.c: add ANONYMOUS mechanism
* dbus/dbus-auth-script.c (_dbus_auth_script_run): fix to detect
an empty/no-op auth script; add commands to check that we have or
don't have the expected credentials
2007-06-09 Havoc Pennington <hp@redhat.com>
* bus/policy.c (bus_policy_create_client_policy): gracefully
......
......@@ -218,10 +218,8 @@ auth_set_unix_credentials(DBusAuth *auth,
credentials = _dbus_credentials_new ();
if (credentials == NULL)
{
_dbus_warn ("no memory\n");
return;
}
_dbus_assert_not_reached ("no memory");
if (uid != DBUS_UID_UNSET)
_dbus_credentials_add_unix_uid (credentials, uid);
if (pid != DBUS_PID_UNSET)
......@@ -288,11 +286,14 @@ _dbus_auth_script_run (const DBusString *filename)
state = DBUS_AUTH_STATE_NEED_DISCONNECT;
line_no = 0;
next_iteration:
while (_dbus_string_pop_line (&file, &line))
{
line_no += 1;
/* _dbus_warn ("%s\n", _dbus_string_get_const_data (&line)); */
_dbus_string_delete_leading_blanks (&line);
if (auth != NULL)
......@@ -658,6 +659,30 @@ _dbus_auth_script_run (const DBusString *filename)
goto out;
}
}
else if (_dbus_string_starts_with_c_str (&line,
"EXPECT_HAVE_NO_CREDENTIALS"))
{
DBusCredentials *authorized_identity;
authorized_identity = _dbus_auth_get_identity (auth);
if (!_dbus_credentials_are_empty (authorized_identity))
{
_dbus_warn ("Expected anonymous login or failed login, but some credentials were authorized\n");
goto out;
}
}
else if (_dbus_string_starts_with_c_str (&line,
"EXPECT_HAVE_SOME_CREDENTIALS"))
{
DBusCredentials *authorized_identity;
authorized_identity = _dbus_auth_get_identity (auth);
if (_dbus_credentials_are_empty (authorized_identity))
{
_dbus_warn ("Expected to have some credentials, but we don't\n");
goto out;
}
}
else if (_dbus_string_starts_with_c_str (&line,
"EXPECT"))
{
......@@ -708,8 +733,12 @@ _dbus_auth_script_run (const DBusString *filename)
}
}
if (auth != NULL &&
state == DBUS_AUTH_STATE_AUTHENTICATED)
if (auth == NULL)
{
_dbus_warn ("Auth script is bogus, did not even have CLIENT or SERVER\n");
goto out;
}
else if (state == DBUS_AUTH_STATE_AUTHENTICATED)
{
const DBusString *unused;
......
......@@ -424,6 +424,10 @@ shutdown_mech (DBusAuth *auth)
}
}
/*
* DBUS_COOKIE_SHA1 mechanism
*/
/* 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.
......@@ -982,6 +986,10 @@ handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
_dbus_string_set_length (&auth->challenge, 0);
}
/*
* EXTERNAL mechanism
*/
static dbus_bool_t
handle_server_data_external_mech (DBusAuth *auth,
const DBusString *data)
......@@ -1051,7 +1059,7 @@ handle_server_data_external_mech (DBusAuth *auth,
}
}
if (_dbus_credentials_are_empty(auth->desired_identity))
if (_dbus_credentials_are_empty (auth->desired_identity))
{
_dbus_verbose ("%s: desired user %s is no good\n",
DBUS_AUTH_NAME (auth),
......@@ -1142,13 +1150,120 @@ handle_client_shutdown_external_mech (DBusAuth *auth)
}
/*
* ANONYMOUS mechanism
*/
static dbus_bool_t
handle_server_data_anonymous_mech (DBusAuth *auth,
const DBusString *data)
{
if (_dbus_string_get_length (data) > 0)
{
/* Client is allowed to send "trace" data, the only defined
* meaning is that if it contains '@' it is an email address,
* and otherwise it is anything else, and it's supposed to be
* UTF-8
*/
if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data)))
{
_dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
DBUS_AUTH_NAME (auth));
{
DBusString plaintext;
DBusString encoded;
_dbus_string_init_const (&plaintext, "D-Bus " VERSION);
_dbus_string_init (&encoded);
_dbus_string_hex_encode (&plaintext, 0,
&encoded,
0);
_dbus_verbose ("%s: try '%s'\n",
DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
}
return send_rejected (auth);
}
_dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
DBUS_AUTH_NAME (auth),
_dbus_string_get_const_data (data));
}
/* We want to be anonymous (clear in case some other protocol got midway through I guess) */
_dbus_credentials_clear (auth->desired_identity);
/* Anonymous is always allowed */
if (!send_ok (auth))
return FALSE;
_dbus_verbose ("%s: authenticated client as anonymous\n",
DBUS_AUTH_NAME (auth));
return TRUE;
}
static void
handle_server_shutdown_anonymous_mech (DBusAuth *auth)
{
}
static dbus_bool_t
handle_client_initial_response_anonymous_mech (DBusAuth *auth,
DBusString *response)
{
/* Our initial response is a "trace" string which must be valid UTF-8
* and must be an email address if it contains '@'.
* We just send the dbus implementation info, like a user-agent or
* something, because... why not. There's nothing guaranteed here
* though, we could change it later.
*/
DBusString plaintext;
if (!_dbus_string_init (&plaintext))
return FALSE;
if (!_dbus_string_append (&plaintext,
"libdbus " VERSION))
goto failed;
if (!_dbus_string_hex_encode (&plaintext, 0,
response,
_dbus_string_get_length (response)))
goto failed;
_dbus_string_free (&plaintext);
return TRUE;
failed:
_dbus_string_free (&plaintext);
return FALSE;
}
static dbus_bool_t
handle_client_data_anonymous_mech (DBusAuth *auth,
const DBusString *data)
{
return TRUE;
}
static void
handle_client_shutdown_anonymous_mech (DBusAuth *auth)
{
}
/* Put mechanisms here in order of preference.
* What I eventually want to have is:
* Right now we have:
*
* - EXTERNAL checks socket credentials (or in the future, other info from the OS)
* - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE
* - ANONYMOUS checks nothing but doesn't auth the person as a user
*
* - a mechanism that checks UNIX domain socket credentials
* - a simple magic cookie mechanism like X11 or ICE
* - mechanisms that chain to Cyrus SASL, so we can use anything it
* offers such as Kerberos, X509, whatever.
* We might ideally add a mechanism to chain to Cyrus SASL so we can
* use its mechanisms as well.
*
*/
static const DBusAuthMechanismHandler
......@@ -1169,6 +1284,14 @@ all_mechanisms[] = {
handle_client_data_cookie_sha1_mech,
NULL, NULL,
handle_client_shutdown_cookie_sha1_mech },
{ "ANONYMOUS",
handle_server_data_anonymous_mech,
NULL, NULL,
handle_server_shutdown_anonymous_mech,
handle_client_initial_response_anonymous_mech,
handle_client_data_anonymous_mech,
NULL, NULL,
handle_client_shutdown_anonymous_mech },
{ NULL, NULL }
};
......@@ -1881,7 +2004,8 @@ lookup_command_from_name (DBusString *command)
}
static void
goto_state (DBusAuth *auth, const DBusAuthStateData *state)
goto_state (DBusAuth *auth,
const DBusAuthStateData *state)
{
_dbus_verbose ("%s: going from state %s to state %s\n",
DBUS_AUTH_NAME (auth),
......
......@@ -705,43 +705,93 @@ _dbus_string_test (void)
_dbus_string_free (&str);
{
int found,found_len;
_dbus_string_init_const (&str, "012\r\n567\n90");
if (!_dbus_string_find_eol(&str, 0, &found, &found_len) || found != 3 || found_len != 2)
_dbus_assert_not_reached ("Did not find '\\r\\n'");
if (found != 3 || found_len != 2)
_dbus_assert_not_reached ("invalid return values");
if (!_dbus_string_find_eol(&str, 5, &found, &found_len))
_dbus_assert_not_reached ("Did not find '\\n'");
if (found != 8 || found_len != 1)
_dbus_assert_not_reached ("invalid return values");
if (_dbus_string_find_eol(&str, 9, &found, &found_len))
_dbus_assert_not_reached ("Found not expected '\\n'");
else if (found != 11 || found_len != 0)
_dbus_assert_not_reached ("invalid return values '\\n'");
_dbus_string_free (&str);
}
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */
int found, found_len;
_dbus_string_init_const (&str, "012\r\n567\n90");
if (!_dbus_string_find_eol (&str, 0, &found, &found_len) || found != 3 || found_len != 2)
_dbus_assert_not_reached ("Did not find '\\r\\n'");
if (found != 3 || found_len != 2)
_dbus_assert_not_reached ("invalid return values");
if (!_dbus_string_find_eol (&str, 5, &found, &found_len))
_dbus_assert_not_reached ("Did not find '\\n'");
if (found != 8 || found_len != 1)
_dbus_assert_not_reached ("invalid return values");
if (_dbus_string_find_eol (&str, 9, &found, &found_len))
_dbus_assert_not_reached ("Found not expected '\\n'");
else if (found != 11 || found_len != 0)
_dbus_assert_not_reached ("invalid return values '\\n'");
found = -1;
found_len = -1;
_dbus_string_init_const (&str, "");
if (_dbus_string_find_eol (&str, 0, &found, &found_len))
_dbus_assert_not_reached ("found an eol in an empty string");
_dbus_assert (found == 0);
_dbus_assert (found_len == 0);
found = -1;
found_len = -1;
_dbus_string_init_const (&str, "foobar");
if (_dbus_string_find_eol (&str, 0, &found, &found_len))
_dbus_assert_not_reached ("found eol in string that lacks one");
_dbus_assert (found == 6);
_dbus_assert (found_len == 0);
found = -1;
found_len = -1;
_dbus_string_init_const (&str, "foobar\n");
if (!_dbus_string_find_eol (&str, 0, &found, &found_len))
_dbus_assert_not_reached ("did not find eol in string that has one at end");
_dbus_assert (found == 6);
_dbus_assert (found_len == 1);
}
{
DBusString line;
#define FIRST_LINE "this is a line"
#define SECOND_LINE "this is a second line"
/* third line is empty */
#define THIRD_LINE ""
#define FOURTH_LINE "this is a fourth line"
if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("no memory");
if (!_dbus_string_append (&str, FIRST_LINE "\n" SECOND_LINE "\r\n" THIRD_LINE "\n" FOURTH_LINE))
_dbus_assert_not_reached ("no memory");
if (!_dbus_string_init (&line))
_dbus_assert_not_reached ("no memory");
if (!_dbus_string_pop_line (&str, &line))
_dbus_assert_not_reached ("failed to pop first line");
_dbus_assert (_dbus_string_equal_c_str (&line, FIRST_LINE));
if (!_dbus_string_pop_line (&str, &line))
_dbus_assert_not_reached ("failed to pop second line");
_dbus_assert (_dbus_string_equal_c_str (&line, SECOND_LINE));
if (!_dbus_string_pop_line (&str, &line))
_dbus_assert_not_reached ("failed to pop third line");
_dbus_assert (_dbus_string_equal_c_str (&line, THIRD_LINE));
if (!_dbus_string_pop_line (&str, &line))
_dbus_assert_not_reached ("failed to pop fourth line");
_dbus_assert (_dbus_string_equal_c_str (&line, FOURTH_LINE));
_dbus_string_free (&str);
_dbus_string_free (&line);
}
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */
......@@ -1804,9 +1804,9 @@ _dbus_string_find (const DBusString *str,
*/
dbus_bool_t
_dbus_string_find_eol (const DBusString *str,
int start,
int *found,
int *found_len)
int start,
int *found,
int *found_len)
{
int i;
......@@ -1843,7 +1843,7 @@ _dbus_string_find_eol (const DBusString *str,
if (found_len)
*found_len = 1;
return TRUE;
}
}
++i;
}
......@@ -2093,17 +2093,33 @@ _dbus_string_pop_line (DBusString *source,
_dbus_string_set_length (dest, 0);
eol = 0;
eol_len = 0;
if (!_dbus_string_find_eol (source, 0, &eol, &eol_len))
eol = _dbus_string_get_length (source);
{
_dbus_assert (eol == _dbus_string_get_length (source));
if (eol == 0)
{
/* If there's no newline and source has zero length, we're done */
return FALSE;
}
/* otherwise, the last line of the file has no eol characters */
}
if (eol == 0)
return FALSE; /* eof */
/* remember eol can be 0 if it's an empty line, but eol_len should not be zero also
* since find_eol returned TRUE
*/
if (!_dbus_string_move_len (source, 0, eol + eol_len, dest, 0))
return FALSE;
return FALSE;
/* remove line ending */
return _dbus_string_set_length(dest, eol);
if (!_dbus_string_set_length (dest, eol))
{
_dbus_assert_not_reached ("out of memory when shortening a string");
return FALSE;
}
return TRUE;
}
#ifdef DBUS_BUILD_TESTS
......
## this tests that a client can login anonymously
CLIENT
## Reject whatever mechanism the client picks first
EXPECT_COMMAND AUTH
SEND 'REJECTED DBUS_TEST_NONEXISTENT_MECH1 ANONYMOUS DBUS_TEST_NONEXISTENT_MECH2'
## And this time we get ANONYMOUS
EXPECT_COMMAND AUTH
## of course real DBUS_COOKIE_SHA1 would not send this here...
SEND 'OK 1234deadbeef'
EXPECT_COMMAND BEGIN
EXPECT_STATE AUTHENTICATED
## this tests the server side in a successful auth of type ANONYMOUS
SERVER
## verify that prior to doing anything, we haven't authed as anyone
EXPECT_HAVE_NO_CREDENTIALS
SEND 'AUTH ANONYMOUS 442d42757320312e312e31'
EXPECT_COMMAND OK
EXPECT_STATE WAITING_FOR_INPUT
SEND 'BEGIN'
EXPECT_STATE AUTHENTICATED
## verify that we are still anonymous
EXPECT_HAVE_NO_CREDENTIALS
......@@ -2,7 +2,10 @@
SERVER
NO_CREDENTIALS
## verify that prior to doing anything, we haven't authed as anyone
EXPECT_HAVE_NO_CREDENTIALS
SEND 'AUTH EXTERNAL USERID_HEX'
EXPECT_COMMAND REJECTED
EXPECT_STATE WAITING_FOR_INPUT
## verify that we still haven't authed as anyone
EXPECT_HAVE_NO_CREDENTIALS
......@@ -2,7 +2,8 @@
SERVER
ROOT_CREDENTIALS
SEND 'AUTH EXTERNAL USERID_HEX'
## 30 is ASCII '0' in hex
SEND 'AUTH EXTERNAL 30'
EXPECT_COMMAND OK
EXPECT_STATE WAITING_FOR_INPUT
SEND 'BEGIN'
......
## this tests we can't auth with silly credentials
## this tests we can't auth if socket reports silly credentials but we ask for our own uid
SERVER
## verify that prior to doing anything, we haven't authed as anyone
EXPECT_HAVE_NO_CREDENTIALS
SILLY_CREDENTIALS
SEND 'AUTH EXTERNAL USERID_HEX'
EXPECT_COMMAND REJECTED
EXPECT_STATE WAITING_FOR_INPUT
## verify that we still haven't authed as anyone
EXPECT_HAVE_NO_CREDENTIALS
## this tests a successful auth of type EXTERNAL
SERVER
## verify that prior to doing anything, we haven't authed as anyone
EXPECT_HAVE_NO_CREDENTIALS
SEND 'AUTH EXTERNAL USERID_HEX'
EXPECT_COMMAND OK
EXPECT_STATE WAITING_FOR_INPUT
SEND 'BEGIN'
EXPECT_STATE AUTHENTICATED
## verify that we now have some credentials
EXPECT_HAVE_SOME_CREDENTIALS
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment