From b3ef8b0e9bd2719d502c7f2e0cf829e151386162 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 27 Dec 2002 02:07:21 +0000 Subject: 2002-12-26 Havoc Pennington * dbus/dbus-auth.c: fixes fixes fixes * dbus/dbus-transport-unix.c: wire up support for encoding/decoding data on the wire * dbus/dbus-auth.c (_dbus_auth_encode_data) (_dbus_auth_decode_data): append to target string instead of nuking it. --- ChangeLog | 11 ++ dbus/dbus-auth.c | 135 +++++++++++++--------- dbus/dbus-internals.h | 9 +- dbus/dbus-marshal.c | 19 ++++ dbus/dbus-string.c | 2 + dbus/dbus-sysdeps.c | 11 ++ dbus/dbus-transport-unix.c | 276 ++++++++++++++++++++++++++++++++++++--------- 7 files changed, 353 insertions(+), 110 deletions(-) diff --git a/ChangeLog b/ChangeLog index a43ef421..bd1c414f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2002-12-26 Havoc Pennington + + * dbus/dbus-auth.c: fixes fixes fixes + + * dbus/dbus-transport-unix.c: wire up support for + encoding/decoding data on the wire + + * dbus/dbus-auth.c (_dbus_auth_encode_data) + (_dbus_auth_decode_data): append to target string + instead of nuking it. + 2002-12-26 Havoc Pennington * dbus/dbus-marshal.h (DBUS_COMPILER_BYTE_ORDER): #ifdef diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index 566abaed..d39a7770 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -173,6 +173,9 @@ static dbus_bool_t process_error_client (DBusAuth *auth, const DBusString *args); +static dbus_bool_t client_try_next_mechanism (DBusAuth *auth); + + static DBusAuthCommandHandler server_handlers[] = { { "AUTH", process_auth }, @@ -331,7 +334,8 @@ handle_encode_stupid_test_mech (DBusAuth *auth, const DBusString *plaintext, DBusString *encoded) { - if (!_dbus_string_base64_encode (plaintext, 0, encoded, 0)) + if (!_dbus_string_base64_encode (plaintext, 0, encoded, + _dbus_string_get_length (encoded))) return FALSE; return TRUE; @@ -342,7 +346,8 @@ handle_decode_stupid_test_mech (DBusAuth *auth, const DBusString *encoded, DBusString *plaintext) { - if (!_dbus_string_base64_decode (encoded, 0, plaintext, 0)) + if (!_dbus_string_base64_decode (encoded, 0, plaintext, + _dbus_string_get_length (plaintext))) return FALSE; return TRUE; @@ -678,6 +683,58 @@ process_mechanisms (DBusAuth *auth, return FALSE; } +static dbus_bool_t +client_try_next_mechanism (DBusAuth *auth) +{ + const DBusAuthMechanismHandler *mech; + DBusString auth_command; + + if (DBUS_AUTH_CLIENT (auth)->mechs_to_try == NULL) + return FALSE; + + mech = DBUS_AUTH_CLIENT (auth)->mechs_to_try->data; + + if (!_dbus_string_init (&auth_command, _DBUS_INT_MAX)) + return FALSE; + + if (!_dbus_string_append (&auth_command, + "AUTH ")) + { + _dbus_string_free (&auth_command); + return FALSE; + } + + if (!_dbus_string_append (&auth_command, + mech->mechanism)) + { + _dbus_string_free (&auth_command); + return FALSE; + } + + if (!_dbus_string_append (&auth_command, + "\r\n")) + { + _dbus_string_free (&auth_command); + return FALSE; + } + + if (!_dbus_string_copy (&auth_command, 0, + &auth->outgoing, + _dbus_string_get_length (&auth->outgoing))) + { + _dbus_string_free (&auth_command); + return FALSE; + } + + auth->mech = mech; + _dbus_list_pop_first (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); + + _dbus_verbose ("Trying mechanism %s\n", + auth->mech->mechanism); + + return TRUE; +} + static dbus_bool_t process_rejected (DBusAuth *auth, const DBusString *command, @@ -694,49 +751,7 @@ process_rejected (DBusAuth *auth, } else if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL) { - /* Try next mechanism */ - const DBusAuthMechanismHandler *mech; - DBusString auth_command; - - mech = DBUS_AUTH_CLIENT (auth)->mechs_to_try->data; - - if (!_dbus_string_init (&auth_command, _DBUS_INT_MAX)) - return FALSE; - - if (!_dbus_string_append (&auth_command, - "AUTH ")) - { - _dbus_string_free (&auth_command); - return FALSE; - } - - if (!_dbus_string_append (&auth->outgoing, - mech->mechanism)) - { - _dbus_string_free (&auth_command); - return FALSE; - } - - if (!_dbus_string_append (&auth->outgoing, - "\r\n")) - { - _dbus_string_free (&auth_command); - return FALSE; - } - - if (!_dbus_string_copy (&auth_command, 0, - &auth->outgoing, - _dbus_string_get_length (&auth->outgoing))) - { - _dbus_string_free (&auth_command); - return FALSE; - } - - auth->mech = mech; - _dbus_list_pop_first (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); - - _dbus_verbose ("Trying mechanism %s\n", - auth->mech->mechanism); + client_try_next_mechanism (auth); } else { @@ -978,9 +993,16 @@ _dbus_auth_client_new (void) auth->handlers = client_handlers; - /* Request an auth */ - if (!_dbus_string_append (&auth->outgoing, - "AUTH DBUS_STUPID_TEST_MECH\r\n")) + /* Add a default mechanism to try */ + if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, + (void*) &all_mechanisms[0])) + { + _dbus_auth_unref (auth); + return NULL; + } + + /* Now try the mechanism we just added */ + if (!client_try_next_mechanism (auth)) { _dbus_auth_unref (auth); return NULL; @@ -1215,7 +1237,7 @@ _dbus_auth_needs_encoding (DBusAuth *auth) * * @param auth the auth conversation * @param plaintext the plain text data - * @param encoded initialized string to fill in with encoded data + * @param encoded initialized string to where encoded data is appended * @returns #TRUE if we had enough memory and successfully encoded */ dbus_bool_t @@ -1223,6 +1245,8 @@ _dbus_auth_encode_data (DBusAuth *auth, const DBusString *plaintext, DBusString *encoded) { + _dbus_assert (plaintext != encoded); + if (!auth->authenticated) return FALSE; @@ -1235,7 +1259,8 @@ _dbus_auth_encode_data (DBusAuth *auth, } else { - return _dbus_string_copy (plaintext, 0, encoded, 0); + return _dbus_string_copy (plaintext, 0, encoded, + _dbus_string_get_length (encoded)); } } @@ -1270,9 +1295,12 @@ _dbus_auth_needs_decoding (DBusAuth *auth) * the peer. If no encoding was negotiated, just copies the bytes (you * can avoid this by checking _dbus_auth_needs_decoding()). * + * @todo We need to be able to distinguish "out of memory" error + * from "the data is hosed" error. + * * @param auth the auth conversation * @param encoded the encoded data - * @param plaintext initialized string to fill in with decoded data + * @param plaintext initialized string where decoded data is appended * @returns #TRUE if we had enough memory and successfully decoded */ dbus_bool_t @@ -1280,6 +1308,8 @@ _dbus_auth_decode_data (DBusAuth *auth, const DBusString *encoded, DBusString *plaintext) { + _dbus_assert (plaintext != encoded); + if (!auth->authenticated) return FALSE; @@ -1292,7 +1322,8 @@ _dbus_auth_decode_data (DBusAuth *auth, } else { - return _dbus_string_copy (encoded, 0, plaintext, 0); + return _dbus_string_copy (encoded, 0, plaintext, + _dbus_string_get_length (plaintext)); } } diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 2b7772f3..027b3ef6 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -83,8 +83,13 @@ typedef void (* DBusForeachFunction) (void *element, dbus_bool_t _dbus_set_fd_nonblocking (int fd, DBusResultCode *result); -void _dbus_verbose_bytes (const unsigned char *data, - int len); +void _dbus_verbose_bytes (const unsigned char *data, + int len); +void _dbus_verbose_bytes_of_string (const DBusString *str, + int start, + int len); + + DBUS_END_DECLS; diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 9fbfb4e1..d8d0d5f7 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -342,6 +342,25 @@ _dbus_verbose_bytes (const unsigned char *data, _dbus_verbose ("\n"); } +/** + * Dump the given part of the string to verbose log. + * + * @param str the string + * @param start the start of range to dump + * @param len length of range + */ +void +_dbus_verbose_bytes_of_string (const DBusString *str, + int start, + int len) +{ + const char *d; + + _dbus_string_get_const_data_len (str, &d, start, len); + + _dbus_verbose_bytes (d, len); +} + /** @} */ #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index c4a51d5b..6dc28577 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -1407,6 +1407,7 @@ _dbus_string_base64_encode (const DBusString *source, const unsigned char *triplet_end; const unsigned char *final_end; DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); + _dbus_assert (source != dest); /* For each 24 bits (3 bytes) of input, we have 4 chars of * output. @@ -1508,6 +1509,7 @@ _dbus_string_base64_decode (const DBusString *source, int sextet_count; int pad_count; DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); + _dbus_assert (source != dest); source_len = real_source->len - start; s = real_source->str + start; diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 76b9c5ce..fed88144 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -116,6 +116,12 @@ _dbus_read (int fd, { /* put length back (doesn't actually realloc) */ _dbus_string_set_length (buffer, start + bytes_read); + +#if 0 + if (bytes_read > 0) + _dbus_verbose_bytes_of_string (buffer, start, bytes_read); +#endif + return bytes_read; } } @@ -148,6 +154,11 @@ _dbus_write (int fd, if (errno == EINTR) goto again; +#if 0 + if (bytes_written > 0) + _dbus_verbose_bytes_of_string (buffer, start, bytes_written); +#endif + return bytes_written; } diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c index c1487a0f..dd0c6833 100644 --- a/dbus/dbus-transport-unix.c +++ b/dbus/dbus-transport-unix.c @@ -61,6 +61,9 @@ struct DBusTransportUnix * outgoing message that have * been written. */ + DBusString encoded_message; /**< Encoded version of current + * outgoing message. + */ }; static void @@ -95,6 +98,8 @@ unix_finalize (DBusTransport *transport) DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; free_watches (transport); + + _dbus_string_free (&unix_transport->encoded_message); _dbus_transport_finalize_base (transport); @@ -291,6 +296,100 @@ write_data_from_auth (DBusTransport *transport) return FALSE; } +static void +recover_unused_bytes (DBusTransport *transport) +{ + + if (_dbus_auth_needs_decoding (transport->auth)) + { + DBusString plaintext; + DBusString encoded; + DBusString *buffer; + int orig_len; + + if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX)) + goto nomem; + + if (!_dbus_string_init (&encoded, _DBUS_INT_MAX)) + { + _dbus_string_free (&plaintext); + goto nomem; + } + + if (!_dbus_auth_get_unused_bytes (transport->auth, + &encoded)) + { + _dbus_string_free (&plaintext); + _dbus_string_free (&encoded); + goto nomem; + } + + if (!_dbus_auth_decode_data (transport->auth, + &encoded, &plaintext)) + { + _dbus_string_free (&plaintext); + _dbus_string_free (&encoded); + goto nomem; + } + + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + orig_len = _dbus_string_get_length (buffer); + + if (!_dbus_string_move (&plaintext, 0, buffer, + orig_len)) + { + _dbus_string_free (&plaintext); + _dbus_string_free (&encoded); + goto nomem; + } + + _dbus_verbose (" %d unused bytes sent to message loader\n", + _dbus_string_get_length (buffer) - + orig_len); + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + _dbus_string_get_length (buffer) - + orig_len); + + _dbus_string_free (&plaintext); + _dbus_string_free (&encoded); + } + else + { + DBusString *buffer; + int orig_len; + + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + orig_len = _dbus_string_get_length (buffer); + + if (!_dbus_auth_get_unused_bytes (transport->auth, + buffer)) + goto nomem; + + _dbus_verbose (" %d unused bytes sent to message loader\n", + _dbus_string_get_length (buffer) - + orig_len); + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + _dbus_string_get_length (buffer) - + orig_len); + } + + queue_messages (transport); + + return; + + nomem: + _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n"); + do_io_error (transport); +} + static void do_authentication (DBusTransport *transport, dbus_bool_t do_reading, @@ -327,35 +426,8 @@ do_authentication (DBusTransport *transport, break; case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES: - { - DBusString *buffer; - int orig_len; - - _dbus_verbose (" auth state: auth with unused bytes\n"); - - _dbus_message_loader_get_buffer (transport->loader, - &buffer); - - orig_len = _dbus_string_get_length (buffer); - - if (!_dbus_auth_get_unused_bytes (transport->auth, - buffer)) - { - _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n"); - do_io_error (transport); - } - - _dbus_verbose (" %d unused bytes sent to message loader\n", - _dbus_string_get_length (buffer) - - orig_len); - - _dbus_message_loader_return_buffer (transport->loader, - buffer, - _dbus_string_get_length (buffer) - - orig_len); - - queue_messages (transport); - } + _dbus_verbose (" auth state: auth with unused bytes\n"); + recover_unused_bytes (transport); break; case DBUS_AUTH_STATE_AUTHENTICATED: @@ -392,6 +464,7 @@ do_writing (DBusTransport *transport) const DBusString *header; const DBusString *body; int header_len, body_len; + int total_bytes_to_write; if (total > unix_transport->max_bytes_written_per_iteration) { @@ -404,30 +477,67 @@ do_writing (DBusTransport *transport) _dbus_assert (message != NULL); _dbus_message_lock (message); + _dbus_verbose ("writing message %p\n", message); + _dbus_message_get_network_data (message, &header, &body); header_len = _dbus_string_get_length (header); body_len = _dbus_string_get_length (body); - - if (unix_transport->message_bytes_written < header_len) + + if (_dbus_auth_needs_encoding (transport->auth)) { + if (_dbus_string_get_length (&unix_transport->encoded_message) == 0) + { + if (!_dbus_auth_encode_data (transport->auth, + header, &unix_transport->encoded_message)) + goto out; + + if (!_dbus_auth_encode_data (transport->auth, + body, &unix_transport->encoded_message)) + { + _dbus_string_set_length (&unix_transport->encoded_message, 0); + goto out; + } + } + + total_bytes_to_write = _dbus_string_get_length (&unix_transport->encoded_message); + + _dbus_verbose ("encoded message is %d bytes\n", + total_bytes_to_write); + bytes_written = - _dbus_write_two (unix_transport->fd, - header, - unix_transport->message_bytes_written, - header_len - unix_transport->message_bytes_written, - body, - 0, body_len); + _dbus_write (unix_transport->fd, + &unix_transport->encoded_message, + unix_transport->message_bytes_written, + total_bytes_to_write - unix_transport->message_bytes_written); } else { - bytes_written = - _dbus_write (unix_transport->fd, - body, - (unix_transport->message_bytes_written - header_len), - body_len - - (unix_transport->message_bytes_written - header_len)); + total_bytes_to_write = header_len + body_len; + + _dbus_verbose ("message is %d bytes\n", + total_bytes_to_write); + + if (unix_transport->message_bytes_written < header_len) + { + bytes_written = + _dbus_write_two (unix_transport->fd, + header, + unix_transport->message_bytes_written, + header_len - unix_transport->message_bytes_written, + body, + 0, body_len); + } + else + { + bytes_written = + _dbus_write (unix_transport->fd, + body, + (unix_transport->message_bytes_written - header_len), + body_len - + (unix_transport->message_bytes_written - header_len)); + } } if (bytes_written < 0) @@ -447,19 +557,22 @@ do_writing (DBusTransport *transport) } else { - _dbus_verbose (" wrote %d bytes\n", bytes_written); + _dbus_verbose (" wrote %d bytes of %d\n", bytes_written, + total_bytes_to_write); total += bytes_written; unix_transport->message_bytes_written += bytes_written; _dbus_assert (unix_transport->message_bytes_written <= - (header_len + body_len)); + total_bytes_to_write); - if (unix_transport->message_bytes_written == (header_len + body_len)) + if (unix_transport->message_bytes_written == total_bytes_to_write) { + unix_transport->message_bytes_written = 0; + _dbus_string_set_length (&unix_transport->encoded_message, 0); + _dbus_connection_message_sent (transport->connection, message); - unix_transport->message_bytes_written = 0; } } } @@ -493,16 +606,59 @@ do_reading (DBusTransport *transport) if (transport->disconnected) goto out; - - _dbus_message_loader_get_buffer (transport->loader, - &buffer); - - bytes_read = _dbus_read (unix_transport->fd, - buffer, unix_transport->max_bytes_read_per_iteration); - _dbus_message_loader_return_buffer (transport->loader, - buffer, - bytes_read < 0 ? 0 : bytes_read); + if (_dbus_auth_needs_decoding (transport->auth)) + { + DBusString encoded; + + if (!_dbus_string_init (&encoded, _DBUS_INT_MAX)) + goto out; /* not enough memory for the moment */ + + bytes_read = _dbus_read (unix_transport->fd, + &encoded, + unix_transport->max_bytes_read_per_iteration); + + if (bytes_read > 0) + { + int orig_len; + + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + orig_len = _dbus_string_get_length (buffer); + + if (!_dbus_auth_decode_data (transport->auth, + &encoded, buffer)) + { + /* FIXME argh, we are really fucked here - nowhere to + * put "encoded" while we wait for more memory. Just + * screw it for now and disconnect. The failure may be + * due to badly-encoded data instead of lack of memory + * anyhow. + */ + _dbus_verbose ("Disconnected from remote app due to failure decoding data\n"); + do_io_error (transport); + } + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + _dbus_string_get_length (buffer) - orig_len); + } + + _dbus_string_free (&encoded); + } + else + { + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + bytes_read = _dbus_read (unix_transport->fd, + buffer, unix_transport->max_bytes_read_per_iteration); + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + bytes_read < 0 ? 0 : bytes_read); + } if (bytes_read < 0) { @@ -748,10 +904,18 @@ _dbus_transport_new_for_fd (int fd, if (unix_transport == NULL) return NULL; + if (!_dbus_string_init (&unix_transport->encoded_message, + _DBUS_INT_MAX)) + { + dbus_free (unix_transport); + return NULL; + } + if (!_dbus_transport_init_base (&unix_transport->base, &unix_vtable, server)) { + _dbus_string_free (&unix_transport->encoded_message); dbus_free (unix_transport); return NULL; } -- cgit