From a789b7b38cb4f4540a41444cbd64bf7ada2d60d2 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 10 Jun 2007 04:54:45 +0000 Subject: 2007-06-09 Havoc Pennington * 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 --- dbus/dbus-auth-script.c | 41 +++++++++++--- dbus/dbus-auth.c | 138 +++++++++++++++++++++++++++++++++++++++++++++--- dbus/dbus-string-util.c | 112 ++++++++++++++++++++++++++++----------- dbus/dbus-string.c | 36 +++++++++---- 4 files changed, 273 insertions(+), 54 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-auth-script.c b/dbus/dbus-auth-script.c index 5aa17d4b..dd864ca5 100644 --- a/dbus/dbus-auth-script.c +++ b/dbus/dbus-auth-script.c @@ -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; diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index b1d57a49..657f8d3d 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -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), diff --git a/dbus/dbus-string-util.c b/dbus/dbus-string-util.c index 16a79340..27bd23a1 100644 --- a/dbus/dbus-string-util.c +++ b/dbus/dbus-string-util.c @@ -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 */ diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index d83a3f39..6177a751 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -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 -- cgit