GUACAMOLE-221: Rollback changes to SSH protocol prompting
This commit is contained in:
parent
b6d3edb749
commit
6605f217c5
@ -26,19 +26,19 @@
|
|||||||
#include <libssh2.h>
|
#include <libssh2.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handler function for retrieving additional credentials from the client.
|
* Handler for retrieving additional credentials.
|
||||||
*
|
*
|
||||||
* @param client
|
* @param client
|
||||||
* The Guacamole Client associated with this need for additional
|
* The Guacamole Client associated with this need for additional
|
||||||
* credentials.
|
* credentials.
|
||||||
*
|
*
|
||||||
* @param cred_name
|
* @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
|
* @return
|
||||||
* A newly-allocated string containing the credentials to be requested from
|
* A newly-allocated string containing the credentials provided by
|
||||||
* the client, or NULL if the credentials will be updated via the required
|
* the user, which must be freed by a call to free().
|
||||||
* instruction.
|
|
||||||
*/
|
*/
|
||||||
typedef char* guac_ssh_credential_handler(guac_client* client, char* cred_name);
|
typedef char* guac_ssh_credential_handler(guac_client* client, char* cred_name);
|
||||||
|
|
||||||
|
@ -359,13 +359,8 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt authentication with username + password. */
|
/* Attempt authentication with username + password. */
|
||||||
if (user->password == NULL && common_session->credential_handler) {
|
if (user->password == NULL && common_session->credential_handler)
|
||||||
|
user->password = common_session->credential_handler(client, "Password: ");
|
||||||
char* password = common_session->credential_handler(client, "password");
|
|
||||||
if (password != NULL)
|
|
||||||
guac_common_ssh_user_set_password(user, password);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Authenticate with password, if provided */
|
/* Authenticate with password, if provided */
|
||||||
if (user->password != NULL) {
|
if (user->password != NULL) {
|
||||||
|
@ -18,10 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "argv.h"
|
#include "argv.h"
|
||||||
#include "common-ssh/user.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "terminal/terminal.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_client* client = user->client;
|
||||||
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
||||||
guac_terminal* terminal = ssh_client->term;
|
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 */
|
/* 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);
|
guac_terminal_apply_color_scheme(terminal, value);
|
||||||
|
|
||||||
/* Update font name */
|
/* Update font name */
|
||||||
|
@ -44,24 +44,6 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_SSH_ARGV_FONT_SIZE "font-size"
|
#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,
|
* Handles a received argument value from a Guacamole "argv" instruction,
|
||||||
* updating the given connection parameter.
|
* updating the given connection parameter.
|
||||||
|
@ -47,15 +47,12 @@ int guac_client_init(guac_client* client) {
|
|||||||
|
|
||||||
/* Init clipboard */
|
/* Init clipboard */
|
||||||
ssh_client->clipboard = guac_common_clipboard_alloc(GUAC_SSH_CLIPBOARD_MAX_LENGTH);
|
ssh_client->clipboard = guac_common_clipboard_alloc(GUAC_SSH_CLIPBOARD_MAX_LENGTH);
|
||||||
|
|
||||||
/* Set handlers */
|
/* Set handlers */
|
||||||
client->join_handler = guac_ssh_user_join_handler;
|
client->join_handler = guac_ssh_user_join_handler;
|
||||||
client->free_handler = guac_ssh_client_free_handler;
|
client->free_handler = guac_ssh_client_free_handler;
|
||||||
|
|
||||||
/* Register handlers for argument values that may be sent after the handshake */
|
/* 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_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_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);
|
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);
|
guac_common_clipboard_free(ssh_client->clipboard);
|
||||||
free(ssh_client);
|
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();
|
guac_common_ssh_uninit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,8 @@ const char* GUAC_SSH_CLIENT_ARGS[] = {
|
|||||||
"hostname",
|
"hostname",
|
||||||
"host-key",
|
"host-key",
|
||||||
"port",
|
"port",
|
||||||
GUAC_SSH_ARGV_USERNAME,
|
"username",
|
||||||
GUAC_SSH_ARGV_PASSWORD,
|
"password",
|
||||||
GUAC_SSH_ARGV_FONT_NAME,
|
GUAC_SSH_ARGV_FONT_NAME,
|
||||||
GUAC_SSH_ARGV_FONT_SIZE,
|
GUAC_SSH_ARGV_FONT_SIZE,
|
||||||
"enable-sftp",
|
"enable-sftp",
|
||||||
@ -45,7 +45,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = {
|
|||||||
"sftp-disable-download",
|
"sftp-disable-download",
|
||||||
"sftp-disable-upload",
|
"sftp-disable-upload",
|
||||||
"private-key",
|
"private-key",
|
||||||
GUAC_SSH_ARGV_PASSPHRASE,
|
"passphrase",
|
||||||
#ifdef ENABLE_SSH_AGENT
|
#ifdef ENABLE_SSH_AGENT
|
||||||
"enable-agent",
|
"enable-agent",
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,92 +57,6 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
* Produces a new user object containing a username and password or private
|
||||||
* key, prompting the user as necessary to obtain that information.
|
* 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;
|
guac_common_ssh_user* user;
|
||||||
|
|
||||||
/* Get username */
|
/* Get username */
|
||||||
if (settings->username == NULL) {
|
if (settings->username == NULL)
|
||||||
|
settings->username = guac_terminal_prompt(ssh_client->term,
|
||||||
char* username = guac_ssh_get_credential(client, GUAC_SSH_ARGV_USERNAME);
|
"Login as: ", true);
|
||||||
if (username != NULL)
|
|
||||||
settings->username = username;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create user object from username */
|
/* Create user object from username */
|
||||||
user = guac_common_ssh_create_user(settings->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)");
|
"Re-attempting private key import (WITH passphrase)");
|
||||||
|
|
||||||
/* Prompt for passphrase if missing */
|
/* Prompt for passphrase if missing */
|
||||||
if (settings->key_passphrase == NULL) {
|
if (settings->key_passphrase == NULL)
|
||||||
|
settings->key_passphrase =
|
||||||
char* passphrase = guac_ssh_get_credential(client, GUAC_SSH_ARGV_PASSPHRASE);
|
guac_terminal_prompt(ssh_client->term,
|
||||||
if (passphrase != NULL)
|
"Key passphrase: ", false);
|
||||||
settings->key_passphrase = passphrase;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reattempt import with passphrase */
|
/* Reattempt import with passphrase */
|
||||||
if (guac_common_ssh_user_import_key(user,
|
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) {
|
void* ssh_input_thread(void* data) {
|
||||||
|
|
||||||
guac_client* client = (guac_client*) data;
|
guac_client* client = (guac_client*) data;
|
||||||
@ -338,6 +268,9 @@ void* ssh_client_thread(void* data) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure connection is kept alive during lengthy connects */
|
||||||
|
guac_socket_require_keep_alive(client->socket);
|
||||||
|
|
||||||
/* Open SSH session */
|
/* Open SSH session */
|
||||||
ssh_client->session = guac_common_ssh_create_session(client,
|
ssh_client->session = guac_common_ssh_create_session(client,
|
||||||
settings->hostname, settings->port, ssh_client->user, settings->server_alive_interval,
|
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->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 */
|
/* Open channel for terminal */
|
||||||
ssh_client->term_channel =
|
ssh_client->term_channel =
|
||||||
@ -564,7 +495,6 @@ void* ssh_client_thread(void* data) {
|
|||||||
guac_client_stop(client);
|
guac_client_stop(client);
|
||||||
pthread_join(input_thread, NULL);
|
pthread_join(input_thread, NULL);
|
||||||
|
|
||||||
pthread_cond_destroy(&ssh_client->ssh_credential_cond);
|
|
||||||
pthread_mutex_destroy(&ssh_client->term_channel_lock);
|
pthread_mutex_destroy(&ssh_client->term_channel_lock);
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_INFO, "SSH connection ended.");
|
guac_client_log(client, GUAC_LOG_INFO, "SSH connection ended.");
|
||||||
|
@ -89,18 +89,6 @@ typedef struct guac_ssh_client {
|
|||||||
* Lock dictating access to the SSH terminal channel.
|
* Lock dictating access to the SSH terminal channel.
|
||||||
*/
|
*/
|
||||||
pthread_mutex_t term_channel_lock;
|
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.
|
* The current clipboard contents.
|
||||||
|
Loading…
Reference in New Issue
Block a user