GUAC-556: Send proper errors for SSH.

This commit is contained in:
Michael Jumper 2014-03-21 19:47:42 -07:00
parent d0dadf6a9c
commit 6e6af91cfa
5 changed files with 47 additions and 79 deletions

View File

@ -35,7 +35,6 @@
#include <unistd.h>
#include <guacamole/client.h>
#include <guacamole/error.h>
#include <guacamole/protocol.h>
#include <guacamole/socket.h>
@ -132,7 +131,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
client_data->term_channel = NULL;
if (argc != SSH_ARGS_COUNT) {
guac_client_log_error(client, "Wrong number of arguments");
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Wrong number of arguments");
return -1;
}
@ -182,8 +181,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
/* Fail if terminal init failed */
if (client_data->term == NULL) {
guac_error = GUAC_STATUS_BAD_STATE;
guac_error_message = "Terminal initialization failed";
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Terminal initialization failed");
return -1;
}
@ -212,7 +210,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
/* Start client thread */
if (pthread_create(&(client_data->client_thread), NULL, ssh_client_thread, (void*) client)) {
guac_client_log_error(client, "Unable to SSH client thread");
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start SSH client thread");
return -1;
}

View File

@ -358,13 +358,14 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
font = pango_font_map_load_font(font_map, context, display->font_desc);
if (font == NULL) {
guac_client_log_error(display->client, "Unable to get font \"%s\"", font_name);
guac_client_abort(display->client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to get font \"%s\"", font_name);
return NULL;
}
metrics = pango_font_get_metrics(font, NULL);
if (metrics == NULL) {
guac_client_log_error(display->client, "Unable to get font metrics for font \"%s\"", font_name);
guac_client_abort(display->client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Unable to get font metrics for font \"%s\"", font_name);
return NULL;
}

View File

@ -37,13 +37,11 @@
#include <guacamole/socket.h>
#include <guacamole/protocol.h>
#include <guacamole/client.h>
#include <guacamole/error.h>
#include <libssh2.h>
#include <pango/pangocairo.h>
int ssh_guac_client_handle_messages(guac_client* client) {
guac_socket* socket = client->socket;
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
char buffer[8192];
@ -72,16 +70,16 @@ int ssh_guac_client_handle_messages(guac_client* client) {
/* Read data, write to terminal */
if ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
if (guac_terminal_write(client_data->term, buffer, bytes_read))
if (guac_terminal_write(client_data->term, buffer, bytes_read)) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error writing data");
return 1;
}
}
/* Notify on error */
if (bytes_read < 0) {
guac_protocol_send_error(socket, "Error reading data.",
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(socket);
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error reading data");
return 1;
}
@ -96,8 +94,7 @@ int ssh_guac_client_handle_messages(guac_client* client) {
}
else if (ret_val < 0) {
guac_error_message = "Error waiting for pipe";
guac_error = GUAC_STATUS_SEE_ERRNO;
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error waiting for data");
return 1;
}

View File

@ -74,8 +74,7 @@ int guac_sftp_file_handler(guac_client* client, guac_stream* stream,
/* Ensure filename is a valid filename and not a path */
if (!__ssh_guac_valid_filename(filename)) {
guac_protocol_send_ack(client->socket, stream,
"SFTP: Illegal filename",
guac_protocol_send_ack(client->socket, stream, "SFTP: Illegal filename",
GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST);
guac_socket_flush(client->socket);
return 0;
@ -103,8 +102,7 @@ int guac_sftp_file_handler(guac_client* client, guac_stream* stream,
/* If path + filename exceeds max length, abort */
if (i == GUAC_SFTP_MAX_PATH) {
guac_protocol_send_ack(client->socket, stream, "SFTP: Name too long",
GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST);
guac_protocol_send_ack(client->socket, stream, "SFTP: Name too long", GUAC_PROTOCOL_STATUS_CLIENT_OVERRUN);
guac_socket_flush(client->socket);
return 0;
}
@ -119,15 +117,13 @@ int guac_sftp_file_handler(guac_client* client, guac_stream* stream,
/* Inform of status */
if (file != NULL) {
guac_protocol_send_ack(client->socket, stream, "SFTP: File opened",
GUAC_PROTOCOL_STATUS_SUCCESS);
guac_protocol_send_ack(client->socket, stream, "SFTP: File opened", GUAC_PROTOCOL_STATUS_SUCCESS);
guac_socket_flush(client->socket);
}
else {
guac_client_log_error(client, "Unable to open file \"%s\": %s",
fullpath, libssh2_sftp_last_error(client_data->sftp_session));
guac_protocol_send_ack(client->socket, stream, "SFTP: Open failed",
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_protocol_send_ack(client->socket, stream, "SFTP: Open failed", GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
guac_socket_flush(client->socket);
}
@ -146,8 +142,7 @@ int guac_sftp_blob_handler(guac_client* client, guac_stream* stream,
/* Attempt write */
if (libssh2_sftp_write(file, data, length) == length) {
guac_protocol_send_ack(client->socket, stream, "SFTP: OK",
GUAC_PROTOCOL_STATUS_SUCCESS);
guac_protocol_send_ack(client->socket, stream, "SFTP: OK", GUAC_PROTOCOL_STATUS_SUCCESS);
guac_socket_flush(client->socket);
}
@ -155,8 +150,7 @@ int guac_sftp_blob_handler(guac_client* client, guac_stream* stream,
else {
guac_client_log_error(client, "Unable to write to file: %s",
libssh2_sftp_last_error(client_data->sftp_session));
guac_protocol_send_ack(client->socket, stream, "SFTP: Write failed",
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_protocol_send_ack(client->socket, stream, "SFTP: Write failed", GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(client->socket);
}
@ -171,14 +165,12 @@ int guac_sftp_end_handler(guac_client* client, guac_stream* stream) {
/* Attempt to close file */
if (libssh2_sftp_close(file) == 0) {
guac_protocol_send_ack(client->socket, stream, "SFTP: OK",
GUAC_PROTOCOL_STATUS_SUCCESS);
guac_protocol_send_ack(client->socket, stream, "SFTP: OK", GUAC_PROTOCOL_STATUS_SUCCESS);
guac_socket_flush(client->socket);
}
else {
guac_client_log_error(client, "Unable to close file");
guac_protocol_send_ack(client->socket, stream, "SFTP: Close failed",
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_protocol_send_ack(client->socket, stream, "SFTP: Close failed", GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(client->socket);
}

View File

@ -168,9 +168,7 @@ static LIBSSH2_SESSION* __guac_ssh_create_session(guac_client* client,
/* Get addresses connection */
if ((retval = getaddrinfo(client_data->hostname, client_data->port,
&hints, &addresses))) {
guac_client_log_error(client,
"Error parsing given address or port: %s",
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error parsing given address or port: %s",
gai_strerror(retval));
return NULL;
@ -188,8 +186,7 @@ static LIBSSH2_SESSION* __guac_ssh_create_session(guac_client* client,
connected_address, sizeof(connected_address),
connected_port, sizeof(connected_port),
NI_NUMERICHOST | NI_NUMERICSERV)))
guac_client_log_error(client, "Unable to resolve host: %s",
gai_strerror(retval));
guac_client_log_info(client, "Unable to resolve host: %s", gai_strerror(retval));
/* Connect */
if (connect(fd, current_address->ai_addr,
@ -215,7 +212,7 @@ static LIBSSH2_SESSION* __guac_ssh_create_session(guac_client* client,
/* If unable to connect to anything, fail */
if (current_address == NULL) {
guac_client_log_error(client, "Unable to connect to any addresses.");
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to connect to any addresses.");
return NULL;
}
@ -226,13 +223,13 @@ static LIBSSH2_SESSION* __guac_ssh_create_session(guac_client* client,
LIBSSH2_SESSION* session = libssh2_session_init_ex(NULL, NULL,
NULL, client);
if (session == NULL) {
guac_client_log_error(client, "Session allocation failed");
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Session allocation failed.");
return NULL;
}
/* Perform handshake */
if (libssh2_session_handshake(session, fd)) {
guac_client_log_error(client, "SSH handshake failed");
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "SSH handshake failed.");
return NULL;
}
@ -250,7 +247,7 @@ static LIBSSH2_SESSION* __guac_ssh_create_session(guac_client* client,
else {
char* error_message;
libssh2_session_last_error(session, &error_message, NULL, 0);
guac_client_log_error(client,
guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
"Public key authentication failed: %s", error_message);
return NULL;
}
@ -264,7 +261,7 @@ static LIBSSH2_SESSION* __guac_ssh_create_session(guac_client* client,
else {
char* error_message;
libssh2_session_last_error(session, &error_message, NULL, 0);
guac_client_log_error(client,
guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
"Password authentication failed: %s", error_message);
return NULL;
}
@ -290,9 +287,8 @@ void* ssh_client_thread(void* data) {
libssh2_init(0);
/* Get username */
if (client_data->username[0] == 0 &&
prompt(client, "Login as: ", client_data->username, sizeof(client_data->username), true) == NULL)
return NULL;
if (client_data->username[0] == 0)
prompt(client, "Login as: ", client_data->username, sizeof(client_data->username), true);
/* Send new name */
snprintf(name, sizeof(name)-1, "%s@%s", client_data->username, client_data->hostname);
@ -309,12 +305,9 @@ void* ssh_client_thread(void* data) {
if (client_data->key == NULL) {
/* Prompt for passphrase if missing */
if (client_data->key_passphrase[0] == 0) {
if (prompt(client, "Key passphrase: ",
client_data->key_passphrase,
sizeof(client_data->key_passphrase), false) == NULL)
return NULL;
}
if (client_data->key_passphrase[0] == 0)
prompt(client, "Key passphrase: ", client_data->key_passphrase,
sizeof(client_data->key_passphrase), false);
/* Import key with passphrase */
client_data->key = ssh_key_alloc(client_data->key_base64,
@ -335,11 +328,8 @@ void* ssh_client_thread(void* data) {
} /* end if key given */
/* Otherwise, get password if not provided */
else if (client_data->password[0] == 0) {
if (prompt(client, "Password: ", client_data->password,
sizeof(client_data->password), false) == NULL)
return NULL;
}
else if (client_data->password[0] == 0)
prompt(client, "Password: ", client_data->password, sizeof(client_data->password), false);
/* Clear screen */
guac_terminal_write_all(stdout_fd, "\x1B[H\x1B[J", 6);
@ -347,19 +337,14 @@ void* ssh_client_thread(void* data) {
/* Open SSH session */
client_data->session = __guac_ssh_create_session(client, &socket_fd);
if (client_data->session == NULL) {
guac_protocol_send_error(socket, "Unable to create SSH session.",
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(socket);
/* Already aborted within __guac_ssh_create_session() */
return NULL;
}
/* Open channel for terminal */
client_data->term_channel =
libssh2_channel_open_session(client_data->session);
client_data->term_channel = libssh2_channel_open_session(client_data->session);
if (client_data->term_channel == NULL) {
guac_protocol_send_error(socket, "Unable to open channel.",
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(socket);
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to open terminal channel.");
return NULL;
}
@ -385,14 +370,15 @@ void* ssh_client_thread(void* data) {
/* Create SSH session specific for SFTP */
guac_client_log_info(client, "Reconnecting for SFTP...");
client_data->sftp_ssh_session = __guac_ssh_create_session(client, NULL);
if (client_data->sftp_ssh_session == NULL) {
/* Already aborted within __guac_ssh_create_session() */
return NULL;
}
/* Request SFTP */
client_data->sftp_session =
libssh2_sftp_init(client_data->sftp_ssh_session);
client_data->sftp_session = libssh2_sftp_init(client_data->sftp_ssh_session);
if (client_data->sftp_session == NULL) {
guac_protocol_send_error(socket, "Unable to start SFTP session..",
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(socket);
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to start SFTP session.");
return NULL;
}
@ -407,21 +393,15 @@ void* ssh_client_thread(void* data) {
}
/* Request PTY */
if (libssh2_channel_request_pty_ex(client_data->term_channel,
"linux", sizeof("linux")-1, NULL, 0,
client_data->term->term_width, client_data->term->term_height,
0, 0)) {
guac_protocol_send_error(socket, "Unable to allocate PTY for channel.",
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(socket);
if (libssh2_channel_request_pty_ex(client_data->term_channel, "linux", sizeof("linux")-1, NULL, 0,
client_data->term->term_width, client_data->term->term_height, 0, 0)) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to allocate PTY.");
return NULL;
}
/* Request shell */
if (libssh2_channel_shell(client_data->term_channel)) {
guac_protocol_send_error(socket, "Unable to associate shell with PTY.",
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(socket);
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to associate shell with PTY.");
return NULL;
}
@ -430,7 +410,7 @@ void* ssh_client_thread(void* data) {
/* Start input thread */
if (pthread_create(&(input_thread), NULL, ssh_input_thread, (void*) client)) {
guac_client_log_error(client, "Unable to start SSH input thread");
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start input thread");
return NULL;
}