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 <unistd.h>
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/error.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/socket.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; client_data->term_channel = NULL;
if (argc != SSH_ARGS_COUNT) { 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; return -1;
} }
@ -182,8 +181,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
/* Fail if terminal init failed */ /* Fail if terminal init failed */
if (client_data->term == NULL) { if (client_data->term == NULL) {
guac_error = GUAC_STATUS_BAD_STATE; guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Terminal initialization failed");
guac_error_message = "Terminal initialization failed";
return -1; return -1;
} }
@ -212,7 +210,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
/* Start client thread */ /* Start client thread */
if (pthread_create(&(client_data->client_thread), NULL, ssh_client_thread, (void*) client)) { 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; 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); font = pango_font_map_load_font(font_map, context, display->font_desc);
if (font == NULL) { 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; return NULL;
} }
metrics = pango_font_get_metrics(font, NULL); metrics = pango_font_get_metrics(font, NULL);
if (metrics == 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; return NULL;
} }

View File

@ -37,13 +37,11 @@
#include <guacamole/socket.h> #include <guacamole/socket.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/error.h>
#include <libssh2.h> #include <libssh2.h>
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
int ssh_guac_client_handle_messages(guac_client* client) { 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; ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
char buffer[8192]; char buffer[8192];
@ -72,16 +70,16 @@ int ssh_guac_client_handle_messages(guac_client* client) {
/* Read data, write to terminal */ /* Read data, write to terminal */
if ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) { 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; return 1;
}
} }
/* Notify on error */ /* Notify on error */
if (bytes_read < 0) { if (bytes_read < 0) {
guac_protocol_send_error(socket, "Error reading data.", guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error reading data");
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(socket);
return 1; return 1;
} }
@ -96,8 +94,7 @@ int ssh_guac_client_handle_messages(guac_client* client) {
} }
else if (ret_val < 0) { else if (ret_val < 0) {
guac_error_message = "Error waiting for pipe"; guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error waiting for data");
guac_error = GUAC_STATUS_SEE_ERRNO;
return 1; 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 */ /* Ensure filename is a valid filename and not a path */
if (!__ssh_guac_valid_filename(filename)) { if (!__ssh_guac_valid_filename(filename)) {
guac_protocol_send_ack(client->socket, stream, guac_protocol_send_ack(client->socket, stream, "SFTP: Illegal filename",
"SFTP: Illegal filename",
GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST); GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
return 0; 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 path + filename exceeds max length, abort */
if (i == GUAC_SFTP_MAX_PATH) { if (i == GUAC_SFTP_MAX_PATH) {
guac_protocol_send_ack(client->socket, stream, "SFTP: Name too long", guac_protocol_send_ack(client->socket, stream, "SFTP: Name too long", GUAC_PROTOCOL_STATUS_CLIENT_OVERRUN);
GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
return 0; return 0;
} }
@ -119,15 +117,13 @@ int guac_sftp_file_handler(guac_client* client, guac_stream* stream,
/* Inform of status */ /* Inform of status */
if (file != NULL) { if (file != NULL) {
guac_protocol_send_ack(client->socket, stream, "SFTP: File opened", guac_protocol_send_ack(client->socket, stream, "SFTP: File opened", GUAC_PROTOCOL_STATUS_SUCCESS);
GUAC_PROTOCOL_STATUS_SUCCESS);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
} }
else { else {
guac_client_log_error(client, "Unable to open file \"%s\": %s", guac_client_log_error(client, "Unable to open file \"%s\": %s",
fullpath, libssh2_sftp_last_error(client_data->sftp_session)); fullpath, libssh2_sftp_last_error(client_data->sftp_session));
guac_protocol_send_ack(client->socket, stream, "SFTP: Open failed", guac_protocol_send_ack(client->socket, stream, "SFTP: Open failed", GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
} }
@ -146,8 +142,7 @@ int guac_sftp_blob_handler(guac_client* client, guac_stream* stream,
/* Attempt write */ /* Attempt write */
if (libssh2_sftp_write(file, data, length) == length) { if (libssh2_sftp_write(file, data, length) == length) {
guac_protocol_send_ack(client->socket, stream, "SFTP: OK", guac_protocol_send_ack(client->socket, stream, "SFTP: OK", GUAC_PROTOCOL_STATUS_SUCCESS);
GUAC_PROTOCOL_STATUS_SUCCESS);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
} }
@ -155,8 +150,7 @@ int guac_sftp_blob_handler(guac_client* client, guac_stream* stream,
else { else {
guac_client_log_error(client, "Unable to write to file: %s", guac_client_log_error(client, "Unable to write to file: %s",
libssh2_sftp_last_error(client_data->sftp_session)); libssh2_sftp_last_error(client_data->sftp_session));
guac_protocol_send_ack(client->socket, stream, "SFTP: Write failed", guac_protocol_send_ack(client->socket, stream, "SFTP: Write failed", GUAC_PROTOCOL_STATUS_SERVER_ERROR);
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
} }
@ -171,14 +165,12 @@ int guac_sftp_end_handler(guac_client* client, guac_stream* stream) {
/* Attempt to close file */ /* Attempt to close file */
if (libssh2_sftp_close(file) == 0) { if (libssh2_sftp_close(file) == 0) {
guac_protocol_send_ack(client->socket, stream, "SFTP: OK", guac_protocol_send_ack(client->socket, stream, "SFTP: OK", GUAC_PROTOCOL_STATUS_SUCCESS);
GUAC_PROTOCOL_STATUS_SUCCESS);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
} }
else { else {
guac_client_log_error(client, "Unable to close file"); guac_client_log_error(client, "Unable to close file");
guac_protocol_send_ack(client->socket, stream, "SFTP: Close failed", guac_protocol_send_ack(client->socket, stream, "SFTP: Close failed", GUAC_PROTOCOL_STATUS_SERVER_ERROR);
GUAC_PROTOCOL_STATUS_SERVER_ERROR);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
} }

View File

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