[WIP] Add SSH tunneling settings for SSH.
This commit is contained in:
parent
4df9687832
commit
8394ef0ed6
@ -22,6 +22,7 @@
|
||||
#include "argv.h"
|
||||
#include "client.h"
|
||||
#include "common-ssh/sftp.h"
|
||||
#include "common-ssh/tunnel.h"
|
||||
#include "ssh.h"
|
||||
#include "terminal/terminal.h"
|
||||
#include "user.h"
|
||||
@ -101,6 +102,9 @@ int guac_ssh_client_free_handler(guac_client* client) {
|
||||
if (ssh_client->recording != NULL)
|
||||
guac_recording_free(ssh_client->recording);
|
||||
|
||||
if (ssh_client->ssh_tunnel != NULL)
|
||||
guac_common_ssh_tunnel_cleanup(ssh_client->ssh_tunnel);
|
||||
|
||||
/* Free interactive SSH session */
|
||||
if (ssh_client->session != NULL)
|
||||
guac_common_ssh_destroy_session(ssh_client->session);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "argv.h"
|
||||
#include "client.h"
|
||||
#include "common/defaults.h"
|
||||
#include "common-ssh/ssh-constants.h"
|
||||
#include "settings.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
@ -47,6 +48,15 @@ const char* GUAC_SSH_CLIENT_ARGS[] = {
|
||||
"sftp-disable-upload",
|
||||
"private-key",
|
||||
"passphrase",
|
||||
"ssh-tunnel",
|
||||
"ssh-tunnel-host",
|
||||
"ssh-tunnel-port",
|
||||
"ssh-tunnel-host-key",
|
||||
"ssh-tunnel-username",
|
||||
"ssh-tunnel-password",
|
||||
"ssh-tunnel-private-key",
|
||||
"ssh-tunnel-passphrase",
|
||||
"ssh-tunnel-alive-interval",
|
||||
#ifdef ENABLE_SSH_AGENT
|
||||
"enable-agent",
|
||||
#endif
|
||||
@ -148,6 +158,55 @@ enum SSH_ARGS_IDX {
|
||||
*/
|
||||
IDX_PASSPHRASE,
|
||||
|
||||
/**
|
||||
* True if SSH tunneling should be enabled. If false or not set, SSH
|
||||
* tunneling will not be used.
|
||||
*/
|
||||
IDX_SSH_TUNNEL,
|
||||
|
||||
/**
|
||||
* The hostname or IP address of the SSH server to use for tunneling.
|
||||
*/
|
||||
IDX_SSH_TUNNEL_HOST,
|
||||
|
||||
/**
|
||||
* The TCP port of the SSH server to use for tunneling.
|
||||
*/
|
||||
IDX_SSH_TUNNEL_PORT,
|
||||
|
||||
/**
|
||||
* If host key checking should be done, the public key of the SSH host
|
||||
* to be used for tunneling.
|
||||
*/
|
||||
IDX_SSH_TUNNEL_HOST_KEY,
|
||||
|
||||
/**
|
||||
* The username for authenticating to the SSH hsot for tunneling.
|
||||
*/
|
||||
IDX_SSH_TUNNEL_USERNAME,
|
||||
|
||||
/**
|
||||
* The password to use to authenticate to the SSH host for tunneling.
|
||||
*/
|
||||
IDX_SSH_TUNNEL_PASSWORD,
|
||||
|
||||
/**
|
||||
* The private key to use to authenticate to the SSH host for tunneling,
|
||||
* as an alternative to password-based authentication.
|
||||
*/
|
||||
IDX_SSH_TUNNEL_PRIVATE_KEY,
|
||||
|
||||
/**
|
||||
* The passphrase to use to decrypt the private key.
|
||||
*/
|
||||
IDX_SSH_TUNNEL_PASSPHRASE,
|
||||
|
||||
/**
|
||||
* The interval at which keepalive packets should be sent to the SSH
|
||||
* tunneling server, or zero if keepalive should be disabled.
|
||||
*/
|
||||
IDX_SSH_TUNNEL_ALIVE_INTERVAL,
|
||||
|
||||
#ifdef ENABLE_SSH_AGENT
|
||||
/**
|
||||
* Whether SSH agent forwarding support should be enabled.
|
||||
@ -418,6 +477,49 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
|
||||
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_DISABLE_UPLOAD, false);
|
||||
|
||||
/* Parse SSH tunneling. */
|
||||
settings->ssh_tunnel =
|
||||
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SSH_TUNNEL, false);
|
||||
|
||||
/* Only parse remaining tunneling settings if it has been enabled. */
|
||||
if (settings->ssh_tunnel) {
|
||||
|
||||
settings->ssh_tunnel_host =
|
||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SSH_TUNNEL_HOST, NULL);
|
||||
|
||||
settings->ssh_tunnel_port =
|
||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SSH_TUNNEL_PORT, GUAC_COMMON_SSH_DEFAULT_PORT);
|
||||
|
||||
settings->ssh_tunnel_host_key =
|
||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SSH_TUNNEL_HOST_KEY, NULL);
|
||||
|
||||
settings->ssh_tunnel_username =
|
||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SSH_TUNNEL_USERNAME, NULL);
|
||||
|
||||
settings->ssh_tunnel_password =
|
||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SSH_TUNNEL_PASSWORD, NULL);
|
||||
|
||||
settings->ssh_tunnel_private_key =
|
||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SSH_TUNNEL_PRIVATE_KEY, NULL);
|
||||
|
||||
settings->ssh_tunnel_passphrase =
|
||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SSH_TUNNEL_PASSPHRASE, NULL);
|
||||
|
||||
settings->ssh_tunnel_alive_interval =
|
||||
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_SSH_TUNNEL_ALIVE_INTERVAL,
|
||||
GUAC_COMMON_SSH_DEFAULT_ALIVE_INTERVAL);
|
||||
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SSH_AGENT
|
||||
settings->enable_agent =
|
||||
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
@ -427,7 +529,7 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
|
||||
/* Read port */
|
||||
settings->port =
|
||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||
IDX_PORT, GUAC_SSH_DEFAULT_PORT);
|
||||
IDX_PORT, GUAC_COMMON_SSH_DEFAULT_PORT);
|
||||
|
||||
/* Read-only mode */
|
||||
settings->read_only =
|
||||
@ -578,6 +680,15 @@ void guac_ssh_settings_free(guac_ssh_settings* settings) {
|
||||
/* Free SFTP settings */
|
||||
free(settings->sftp_root_directory);
|
||||
|
||||
/* Free tunnel settings */
|
||||
free(settings->ssh_tunnel_host);
|
||||
free(settings->ssh_tunnel_host_key);
|
||||
free(settings->ssh_tunnel_port);
|
||||
free(settings->ssh_tunnel_username);
|
||||
free(settings->ssh_tunnel_password);
|
||||
free(settings->ssh_tunnel_private_key);
|
||||
free(settings->ssh_tunnel_passphrase);
|
||||
|
||||
/* Free typescript settings */
|
||||
free(settings->typescript_name);
|
||||
free(settings->typescript_path);
|
||||
|
@ -26,12 +26,6 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* The port to connect to when initiating any SSH connection, if no other port
|
||||
* is specified.
|
||||
*/
|
||||
#define GUAC_SSH_DEFAULT_PORT "22"
|
||||
|
||||
/**
|
||||
* The filename to use for the typescript, if not specified.
|
||||
*/
|
||||
@ -178,6 +172,68 @@ typedef struct guac_ssh_settings {
|
||||
*/
|
||||
bool sftp_disable_upload;
|
||||
|
||||
/**
|
||||
* Whether to enable tunneling of this connection through the specified
|
||||
* SSH server. If set to "true", guacd will attempt to connect to the SSH
|
||||
* server and tunnel all of the traffic through the SSH connection. If
|
||||
* set to "false" or not set, SSH tunneling will not be used.
|
||||
*/
|
||||
bool ssh_tunnel;
|
||||
|
||||
/**
|
||||
* The hostname or address of the host through which traffic should be
|
||||
* tunneled over SSH. If tunneling is enabled, this is required, or the
|
||||
* connection will be aborted.
|
||||
*/
|
||||
char* ssh_tunnel_host;
|
||||
|
||||
/**
|
||||
* The port on which to connect to the SSH server to tunnel traffic, if
|
||||
* SSH tunneling is enabled. If not specified, this will default to 22, the
|
||||
* normal SSH port.
|
||||
*/
|
||||
char* ssh_tunnel_port;
|
||||
|
||||
/**
|
||||
* The public key of the SSH host through which this connection will be
|
||||
* tunneled. If unset, no host key checking will be done and the connection
|
||||
* will be attempted regardless of the identity of the remote host.
|
||||
*/
|
||||
char* ssh_tunnel_host_key;
|
||||
|
||||
/**
|
||||
* The username to use when connecting to the SSH host to tunnel traffic.
|
||||
* This is required if SSH tunneling is enabled.
|
||||
*/
|
||||
char* ssh_tunnel_username;
|
||||
|
||||
/**
|
||||
* The password to use when connecting to the SSH host to tunnel traffic,
|
||||
* if password authentication is used.
|
||||
*/
|
||||
char* ssh_tunnel_password;
|
||||
|
||||
/**
|
||||
* The private key to use to authenticate to the SSH server to tunnel traffic,
|
||||
* if key-based authentication is used.
|
||||
*/
|
||||
char* ssh_tunnel_private_key;
|
||||
|
||||
/**
|
||||
* The passphrase of the private key to use to decrypt the private key when
|
||||
* using key-based authentication, if the key is encrypted.
|
||||
*/
|
||||
char* ssh_tunnel_passphrase;
|
||||
|
||||
/**
|
||||
* The interval at which keepalive messages will be sent to the SSH server
|
||||
* over which the connection is being tunneled. The default is 0, meaning
|
||||
* that keepalive messages will be disabled. The minimum value is 2 to avoid
|
||||
* busy loop scenarios, and a value of 1 is automatically increased to 2 by
|
||||
* the underlying libssh2 implementation.
|
||||
*/
|
||||
int ssh_tunnel_alive_interval;
|
||||
|
||||
#ifdef ENABLE_SSH_AGENT
|
||||
/**
|
||||
* Whether the SSH agent is enabled.
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/recording.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/string.h>
|
||||
#include <guacamole/timestamp.h>
|
||||
#include <guacamole/wol.h>
|
||||
#include <openssl/err.h>
|
||||
@ -226,6 +227,96 @@ void* ssh_client_thread(void* data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (settings->ssh_tunnel) {
|
||||
|
||||
/* Allocate memory for the SSH tunnel data. */
|
||||
ssh_client->ssh_tunnel = malloc(sizeof(guac_ssh_tunnel));
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"SSH tunneling is enabled, connecting via SSH.");
|
||||
|
||||
/* Associate the guac_client object with the tunnel. */
|
||||
ssh_client->ssh_tunnel->client = client;
|
||||
|
||||
/* Abort if tunnel username is missing */
|
||||
if (settings->ssh_tunnel_username == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"An SSH tunnel-specific username is required if "
|
||||
"SSH tunneling is enabled.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_client->ssh_tunnel->user =
|
||||
guac_common_ssh_create_user(settings->ssh_tunnel_username);
|
||||
|
||||
/* Import SSH tunnel private key, if given */
|
||||
if (settings->ssh_tunnel_private_key != NULL) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Authenticating SSH tunnel with private key.");
|
||||
|
||||
/* Abort if SSH tunnel private key cannot be read */
|
||||
if (guac_common_ssh_user_import_key(ssh_client->ssh_tunnel->user,
|
||||
settings->ssh_tunnel_private_key,
|
||||
settings->ssh_tunnel_passphrase)) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"SSH tunnel private key unreadable.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, use specified SSH tunnel password */
|
||||
else {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Authenticating SSH tunnel with password.");
|
||||
|
||||
guac_common_ssh_user_set_password(ssh_client->ssh_tunnel->user,
|
||||
settings->ssh_tunnel_password);
|
||||
|
||||
}
|
||||
|
||||
/* Attempt SSH tunnel connection */
|
||||
ssh_client->ssh_tunnel->session =
|
||||
guac_common_ssh_create_session(client, settings->ssh_tunnel_host,
|
||||
settings->ssh_tunnel_port, ssh_client->ssh_tunnel->user,
|
||||
settings->ssh_tunnel_alive_interval,
|
||||
settings->ssh_tunnel_host_key, NULL);
|
||||
|
||||
/* Fail if SSH tunnel connection does not succeed */
|
||||
if (ssh_client->ssh_tunnel->session == NULL) {
|
||||
/* Already aborted within guac_common_ssh_create_session() */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"SSH session created for tunneling, initializing the tunnel.");
|
||||
|
||||
/* Initialize the tunnel or fail. */
|
||||
if (guac_common_ssh_tunnel_init(ssh_client->ssh_tunnel,
|
||||
settings->hostname, strtol(settings->port, NULL, 10))) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Unable to initialize SSH tunnel, aborting connection.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If tunnel socket is not returned, bail out. */
|
||||
if (ssh_client->ssh_tunnel->socket_path == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Unable to obtain socket for SSH tunnel, aborting.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Overwrite the hostname with the path to the socket and zero out port. */
|
||||
settings->hostname = guac_strdup(ssh_client->ssh_tunnel->socket_path);
|
||||
settings->port = 0;
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"SSH tunnel connection succeeded.");
|
||||
|
||||
}
|
||||
|
||||
char ssh_ttymodes[GUAC_SSH_TTYMODES_SIZE(1)];
|
||||
|
||||
/* Set up screen recording, if requested */
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "common/clipboard.h"
|
||||
#include "common-ssh/sftp.h"
|
||||
#include "common-ssh/ssh.h"
|
||||
#include "common-ssh/tunnel.h"
|
||||
#include "common-ssh/user.h"
|
||||
#include "settings.h"
|
||||
#include "terminal/terminal.h"
|
||||
@ -60,6 +61,11 @@ typedef struct guac_ssh_client {
|
||||
*/
|
||||
pthread_t client_thread;
|
||||
|
||||
/**
|
||||
* If SSH tunneling is enabled, this is the object that tracks the tunnel.
|
||||
*/
|
||||
guac_ssh_tunnel* ssh_tunnel;
|
||||
|
||||
/**
|
||||
* The user and credentials to use for all SSH sessions.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user