diff --git a/src/common-ssh/common-ssh/ssh.h b/src/common-ssh/common-ssh/ssh.h index 336c4b54..346d8abc 100644 --- a/src/common-ssh/common-ssh/ssh.h +++ b/src/common-ssh/common-ssh/ssh.h @@ -26,19 +26,19 @@ #include /** - * A handler function for retrieving additional credentials from the client. + * Handler for retrieving additional credentials. * * @param client * The Guacamole Client associated with this need for additional * credentials. * * @param cred_name - * The connection parameter that is being requested from the client. + * The name of the credential being requested, which will be shared + * with the client in order to generate a meaningful prompt. * * @return - * A newly-allocated string containing the credentials to be requested from - * the client, or NULL if the credentials will be updated via the required - * instruction. + * A newly-allocated string containing the credentials provided by + * the user, which must be freed by a call to free(). */ typedef char* guac_ssh_credential_handler(guac_client* client, char* cred_name); diff --git a/src/common-ssh/ssh.c b/src/common-ssh/ssh.c index af3711f3..c03e984d 100644 --- a/src/common-ssh/ssh.c +++ b/src/common-ssh/ssh.c @@ -359,13 +359,8 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session) } /* Attempt authentication with username + password. */ - if (user->password == NULL && common_session->credential_handler) { - - char* password = common_session->credential_handler(client, "password"); - if (password != NULL) - guac_common_ssh_user_set_password(user, password); - - } + if (user->password == NULL && common_session->credential_handler) + user->password = common_session->credential_handler(client, "Password: "); /* Authenticate with password, if provided */ if (user->password != NULL) { diff --git a/src/protocols/ssh/argv.c b/src/protocols/ssh/argv.c index c6921565..9b3cf653 100644 --- a/src/protocols/ssh/argv.c +++ b/src/protocols/ssh/argv.c @@ -18,10 +18,7 @@ */ #include "config.h" - #include "argv.h" -#include "common-ssh/user.h" -#include "settings.h" #include "ssh.h" #include "terminal/terminal.h" @@ -39,30 +36,9 @@ int guac_ssh_argv_callback(guac_user* user, const char* mimetype, guac_client* client = user->client; guac_ssh_client* ssh_client = (guac_ssh_client*) client->data; guac_terminal* terminal = ssh_client->term; - guac_ssh_settings* settings = ssh_client->settings; - /* Update username */ - if (strcmp(name, GUAC_SSH_ARGV_USERNAME) == 0) { - free(settings->username); - settings->username = strdup(value); - pthread_cond_signal(&ssh_client->ssh_credential_cond); - } - - /* Update password */ - else if (strcmp(name, GUAC_SSH_ARGV_PASSWORD) == 0) { - guac_common_ssh_user_set_password(ssh_client->user, value); - pthread_cond_signal(&ssh_client->ssh_credential_cond); - } - - /* Update private key passphrase */ - else if (strcmp(name, GUAC_SSH_ARGV_PASSPHRASE) == 0) { - free(settings->key_passphrase); - settings->key_passphrase = strdup(value); - pthread_cond_signal(&ssh_client->ssh_credential_cond); - } - /* Update color scheme */ - else if (strcmp(name, GUAC_SSH_ARGV_COLOR_SCHEME) == 0) + if (strcmp(name, GUAC_SSH_ARGV_COLOR_SCHEME) == 0) guac_terminal_apply_color_scheme(terminal, value); /* Update font name */ diff --git a/src/protocols/ssh/argv.h b/src/protocols/ssh/argv.h index 0a726c10..4cbdb4c8 100644 --- a/src/protocols/ssh/argv.h +++ b/src/protocols/ssh/argv.h @@ -44,24 +44,6 @@ */ #define GUAC_SSH_ARGV_FONT_SIZE "font-size" -/** - * The name of the parameter that specifies/updates the username used by the - * connection. - */ -#define GUAC_SSH_ARGV_USERNAME "username" - -/** - * The name of the parameter that specifies/updates the password used by the - * connection. - */ -#define GUAC_SSH_ARGV_PASSWORD "password" - -/** - * The name of the parameter that specifies/updates the private key passphrase - * used by the connection. - */ -#define GUAC_SSH_ARGV_PASSPHRASE "passphrase" - /** * Handles a received argument value from a Guacamole "argv" instruction, * updating the given connection parameter. diff --git a/src/protocols/ssh/client.c b/src/protocols/ssh/client.c index 2a4ec5c9..1bd6647e 100644 --- a/src/protocols/ssh/client.c +++ b/src/protocols/ssh/client.c @@ -47,15 +47,12 @@ int guac_client_init(guac_client* client) { /* Init clipboard */ ssh_client->clipboard = guac_common_clipboard_alloc(GUAC_SSH_CLIPBOARD_MAX_LENGTH); - + /* Set handlers */ client->join_handler = guac_ssh_user_join_handler; client->free_handler = guac_ssh_client_free_handler; /* Register handlers for argument values that may be sent after the handshake */ - guac_argv_register(GUAC_SSH_ARGV_USERNAME, guac_ssh_argv_callback, NULL, 0); - guac_argv_register(GUAC_SSH_ARGV_PASSWORD, guac_ssh_argv_callback, NULL, 0); - guac_argv_register(GUAC_SSH_ARGV_PASSPHRASE, guac_ssh_argv_callback, NULL, 0); guac_argv_register(GUAC_SSH_ARGV_COLOR_SCHEME, guac_ssh_argv_callback, NULL, GUAC_ARGV_OPTION_ECHO); guac_argv_register(GUAC_SSH_ARGV_FONT_NAME, guac_ssh_argv_callback, NULL, GUAC_ARGV_OPTION_ECHO); guac_argv_register(GUAC_SSH_ARGV_FONT_SIZE, guac_ssh_argv_callback, NULL, GUAC_ARGV_OPTION_ECHO); @@ -123,10 +120,6 @@ int guac_ssh_client_free_handler(guac_client* client) { guac_common_clipboard_free(ssh_client->clipboard); free(ssh_client); - /* Destroy the pthread conditional handler */ - pthread_cond_destroy(&(ssh_client->ssh_credential_cond)); - pthread_mutex_destroy(&(ssh_client->ssh_credential_lock)); - guac_common_ssh_uninit(); return 0; } diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index f287c901..242e1d29 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -36,8 +36,8 @@ const char* GUAC_SSH_CLIENT_ARGS[] = { "hostname", "host-key", "port", - GUAC_SSH_ARGV_USERNAME, - GUAC_SSH_ARGV_PASSWORD, + "username", + "password", GUAC_SSH_ARGV_FONT_NAME, GUAC_SSH_ARGV_FONT_SIZE, "enable-sftp", @@ -45,7 +45,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = { "sftp-disable-download", "sftp-disable-upload", "private-key", - GUAC_SSH_ARGV_PASSPHRASE, + "passphrase", #ifdef ENABLE_SSH_AGENT "enable-agent", #endif diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 1a9e2717..03f5b0b6 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -57,92 +57,6 @@ #include #include -/** - * A data structure that maps parameter names of credentials that will be - * prompted to the actual text that will be displayed on the screen. - */ -typedef struct guac_ssh_credential_prompt_map { - - /** - * The parameter name of the credential that is being prompted for. - */ - char* name; - - /** - * The text that will display to the user during the prompt. - */ - char* prompt; - -} guac_ssh_credential_prompt_map; - -/** - * The map of credentials the user can be prompted for to the text displayed - * on the screen. - */ -guac_ssh_credential_prompt_map ssh_credential_prompt_map[] = { - { GUAC_SSH_ARGV_USERNAME, "Login as: " }, - { GUAC_SSH_ARGV_PASSWORD, "Password: " }, - { GUAC_SSH_ARGV_PASSPHRASE, "Key passphrase: " }, - { NULL, NULL} -}; - -/** - * Prompts the user for the credential specified in the cred_name parameter in - * order to continue a SSH connection. If the owner of the connection is running - * a client that supports the "required" instruction this credential will be - * sent to the client with that instruction and updated directly via the argv - * handler. If the client does not support the "required" instruction the prompt - * will be generated directly on the terminal and the value returned through - * this function. - * - * @param client - * The guac_client object associated with the current connection - * where additional credentials are required. - * - * @param cred_name - * The name of the parameter to prompt for in the client. - * - * @return - * If the client does not support the "required" instruction, the value - * provided by the user on the terminal will be returned. NULL will be - * returned if either the client supports the "required" instruction and - * the parameter will be updated directly, or if the parameter specified - * is invalid. - */ -static char* guac_ssh_get_credential(guac_client *client, char* cred_name) { - - guac_ssh_client* ssh_client = (guac_ssh_client*) client->data; - - /* If client owner does not support required, use terminal prompt. */ - if (!guac_client_owner_supports_required(client)) { - - /* Loop to find correct prompt for credential name. */ - guac_ssh_credential_prompt_map* current = ssh_credential_prompt_map; - while (current->name != NULL) { - if (strcmp(current->name, cred_name) == 0) - return guac_terminal_prompt(ssh_client->term, - current->prompt, true); - current++; - } - - /* No matching credential was found, so return NULL. */ - return NULL; - } - - /* Lock the SSH client thread while prompting for the credential. */ - pthread_mutex_lock(&(ssh_client->ssh_credential_lock)); - - /* Let the owner know what we require. */ - guac_client_owner_send_required(client, (const char* []) {cred_name, NULL}); - - /* Wait for the response, and then unlock the thread. */ - pthread_cond_wait(&(ssh_client->ssh_credential_cond), &(ssh_client->ssh_credential_lock)); - pthread_mutex_unlock(&(ssh_client->ssh_credential_lock)); - - return NULL; - -} - /** * Produces a new user object containing a username and password or private * key, prompting the user as necessary to obtain that information. @@ -163,14 +77,10 @@ static guac_common_ssh_user* guac_ssh_get_user(guac_client* client) { guac_common_ssh_user* user; /* Get username */ - if (settings->username == NULL) { - - char* username = guac_ssh_get_credential(client, GUAC_SSH_ARGV_USERNAME); - if (username != NULL) - settings->username = username; + if (settings->username == NULL) + settings->username = guac_terminal_prompt(ssh_client->term, + "Login as: ", true); - } - /* Create user object from username */ user = guac_common_ssh_create_user(settings->username); @@ -193,13 +103,10 @@ static guac_common_ssh_user* guac_ssh_get_user(guac_client* client) { "Re-attempting private key import (WITH passphrase)"); /* Prompt for passphrase if missing */ - if (settings->key_passphrase == NULL) { - - char* passphrase = guac_ssh_get_credential(client, GUAC_SSH_ARGV_PASSPHRASE); - if (passphrase != NULL) - settings->key_passphrase = passphrase; - - } + if (settings->key_passphrase == NULL) + settings->key_passphrase = + guac_terminal_prompt(ssh_client->term, + "Key passphrase: ", false); /* Reattempt import with passphrase */ if (guac_common_ssh_user_import_key(user, @@ -237,6 +144,29 @@ static guac_common_ssh_user* guac_ssh_get_user(guac_client* client) { } +/** + * A function used to generate a terminal prompt to gather additional + * credentials from the guac_client during a connection, and using + * the specified string to generate the prompt for the user. + * + * @param client + * The guac_client object associated with the current connection + * where additional credentials are required. + * + * @param cred_name + * The prompt text to display to the screen when prompting for the + * additional credentials. + * + * @return + * The string of credentials gathered from the user. + */ +static char* guac_ssh_get_credential(guac_client *client, char* cred_name) { + + guac_ssh_client* ssh_client = (guac_ssh_client*) client->data; + return guac_terminal_prompt(ssh_client->term, cred_name, false); + +} + void* ssh_input_thread(void* data) { guac_client* client = (guac_client*) data; @@ -338,6 +268,9 @@ void* ssh_client_thread(void* data) { return NULL; } + /* Ensure connection is kept alive during lengthy connects */ + guac_socket_require_keep_alive(client->socket); + /* Open SSH session */ ssh_client->session = guac_common_ssh_create_session(client, settings->hostname, settings->port, ssh_client->user, settings->server_alive_interval, @@ -348,8 +281,6 @@ void* ssh_client_thread(void* data) { } pthread_mutex_init(&ssh_client->term_channel_lock, NULL); - pthread_mutex_init(&ssh_client->ssh_credential_lock, NULL); - pthread_cond_init(&ssh_client->ssh_credential_cond, NULL); /* Open channel for terminal */ ssh_client->term_channel = @@ -564,7 +495,6 @@ void* ssh_client_thread(void* data) { guac_client_stop(client); pthread_join(input_thread, NULL); - pthread_cond_destroy(&ssh_client->ssh_credential_cond); pthread_mutex_destroy(&ssh_client->term_channel_lock); guac_client_log(client, GUAC_LOG_INFO, "SSH connection ended."); diff --git a/src/protocols/ssh/ssh.h b/src/protocols/ssh/ssh.h index b86ea48f..cb5d8bc5 100644 --- a/src/protocols/ssh/ssh.h +++ b/src/protocols/ssh/ssh.h @@ -89,18 +89,6 @@ typedef struct guac_ssh_client { * Lock dictating access to the SSH terminal channel. */ pthread_mutex_t term_channel_lock; - - /** - * Lock that controls access to updating credential parameters for the - * SSH connection. - */ - pthread_mutex_t ssh_credential_lock; - - /** - * Condition used when the SSH client thread needs to wait for Guacamole - * client to pass additional credentials before continuing the connection. - */ - pthread_cond_t ssh_credential_cond; /** * The current clipboard contents.