diff --git a/src/common-ssh/common-ssh/ssh.h b/src/common-ssh/common-ssh/ssh.h index 986c63b2..d5805b4a 100644 --- a/src/common-ssh/common-ssh/ssh.h +++ b/src/common-ssh/common-ssh/ssh.h @@ -114,6 +114,10 @@ void guac_common_ssh_uninit(); * * @param user * The user to authenticate as, once connected. + * + * @param timeout + * The number of seconds to attempt to connect to the SSH server before + * timing out. * * @param keepalive * How frequently the connection should send keepalive packets, in @@ -138,7 +142,7 @@ void guac_common_ssh_uninit(); */ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, const char* hostname, const char* port, guac_common_ssh_user* user, - int keepalive, const char* host_key, + int timeout, int keepalive, const char* host_key, guac_ssh_credential_handler* credential_handler); /** diff --git a/src/common-ssh/ssh.c b/src/common-ssh/ssh.c index ac786700..edd2240c 100644 --- a/src/common-ssh/ssh.c +++ b/src/common-ssh/ssh.c @@ -35,11 +35,17 @@ #include #include +#include +#include +#include +#include #include #include #include #include #include +#include +#include #include #ifdef LIBSSH2_USES_GCRYPT @@ -408,10 +414,10 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session) guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, const char* hostname, const char* port, guac_common_ssh_user* user, - int keepalive, const char* host_key, + int timeout, int keepalive, const char* host_key, guac_ssh_credential_handler* credential_handler) { - int fd = guac_socket_tcp_connect(hostname, port); + int fd = guac_socket_tcp_connect(hostname, port, timeout); if (fd < 0) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Failed to open TCP connection to %s on %s.", hostname, port); diff --git a/src/libguac/guacamole/socket-tcp.h b/src/libguac/guacamole/socket-tcp.h index 48c0743a..4d13e20b 100644 --- a/src/libguac/guacamole/socket-tcp.h +++ b/src/libguac/guacamole/socket-tcp.h @@ -35,10 +35,13 @@ * @param port * The TCP port to which to attempt to connect. * + * @param timeout + * The number of seconds to try the TCP connection before timing out. + * * @return * A valid socket if the connection succeeds, or a negative integer if it * fails. */ -int guac_socket_tcp_connect(const char* hostname, const char* port); +int guac_socket_tcp_connect(const char* hostname, const char* port, const int timeout); #endif // __GUAC_SOCKET_TCP_H \ No newline at end of file diff --git a/src/libguac/guacamole/wol-constants.h b/src/libguac/guacamole/wol-constants.h index 8b43fd18..831a475e 100644 --- a/src/libguac/guacamole/wol-constants.h +++ b/src/libguac/guacamole/wol-constants.h @@ -33,6 +33,12 @@ */ #define GUAC_WOL_DEFAULT_CONNECT_RETRIES 5 +/** + * The default number of seconds for the connection timeout when attempting + * to connect to the remote system to see if it is awake. + */ +#define GUAC_WOL_DEFAULT_CONNECTION_TIMEOUT 10 + /** * The value for the local IPv4 broadcast address. */ diff --git a/src/libguac/guacamole/wol.h b/src/libguac/guacamole/wol.h index f4c7d66e..21036ed6 100644 --- a/src/libguac/guacamole/wol.h +++ b/src/libguac/guacamole/wol.h @@ -83,6 +83,10 @@ int guac_wol_wake(const char* mac_addr, const char* broadcast_addr, * @param port * The TCP port of the remote system on which the connection will be * attempted after the system has been woken. + * + * @param timeout + * The number of seconds to wait when attempting the connection to the + * remote system when checking to see if it is awake. * * @return * Zero if the packet is successfully sent to the destination; non-zero @@ -90,7 +94,7 @@ int guac_wol_wake(const char* mac_addr, const char* broadcast_addr, */ int guac_wol_wake_and_wait(const char* mac_addr, const char* broadcast_addr, const unsigned short udp_port, int wait_time, int retries, - const char* hostname, const char* port); + const char* hostname, const char* port, const int timeout); #endif /* GUAC_WOL_H */ diff --git a/src/libguac/socket-tcp.c b/src/libguac/socket-tcp.c index 7e41d021..4464ce92 100644 --- a/src/libguac/socket-tcp.c +++ b/src/libguac/socket-tcp.c @@ -22,11 +22,13 @@ #include "guacamole/socket.h" #include +#include #include #include +#include #include -int guac_socket_tcp_connect(const char* hostname, const char* port) { +int guac_socket_tcp_connect(const char* hostname, const char* port, const int timeout) { int retval; @@ -73,15 +75,31 @@ int guac_socket_tcp_connect(const char* hostname, const char* port) { return fd; } - /* Connect */ - if (connect(fd, current_address->ai_addr, - current_address->ai_addrlen) == 0) { + /* Set socket to non-blocking */ + fcntl(fd, F_SETFL, O_NONBLOCK); - /* Done if successful connect */ + /* Set up timeout. */ + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + + struct timeval tv; + tv.tv_sec = timeout; + tv.tv_usec = 0; + + /* Connect and wait for timeout */ + if (connect(fd, current_address->ai_addr, current_address->ai_addrlen) < 0) { + guac_error = GUAC_STATUS_REFUSED; + guac_error_message = "Unable to connect via socket."; + close(fd); break; - } + /* Check for the connection and break if successful */ + if (select(fd + 1, NULL, &fdset, NULL, &tv) > 0) + break; + + /* Connection not successful - free resources and go to the next address. */ close(fd); current_address = current_address->ai_next; diff --git a/src/libguac/wol.c b/src/libguac/wol.c index 29eb5f50..fbaa04d9 100644 --- a/src/libguac/wol.c +++ b/src/libguac/wol.c @@ -201,10 +201,10 @@ int guac_wol_wake(const char* mac_addr, const char* broadcast_addr, int guac_wol_wake_and_wait(const char* mac_addr, const char* broadcast_addr, const unsigned short udp_port, int wait_time, int retries, - const char* hostname, const char* port) { + const char* hostname, const char* port, const int timeout) { /* Attempt to connect, first. */ - int sockfd = guac_socket_tcp_connect(hostname, port); + int sockfd = guac_socket_tcp_connect(hostname, port, timeout); /* If connection succeeds, no need to wake the system. */ if (sockfd > 0) { @@ -225,7 +225,7 @@ int guac_wol_wake_and_wait(const char* mac_addr, const char* broadcast_addr, /* Try to connect on the specified TCP port and hostname or IP. */ for (int i = 0; i < retries; i++) { - sockfd = guac_socket_tcp_connect(hostname, port); + sockfd = guac_socket_tcp_connect(hostname, port, timeout); /* Connection succeeded - close socket and exit. */ if (sockfd > 0) { diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index e8f146f8..4cf8e5f4 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -717,7 +717,8 @@ void* guac_rdp_client_thread(void* data) { settings->wol_wait_time, GUAC_WOL_DEFAULT_CONNECT_RETRIES, settings->hostname, - (const char *) str_port)) { + (const char *) str_port, + GUAC_WOL_DEFAULT_CONNECTION_TIMEOUT)) { guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet, or server failed to wake up."); guac_mem_free(str_port); return NULL; @@ -799,6 +800,33 @@ void* guac_rdp_client_thread(void* data) { return NULL; } + /* Import the public key, if that is specified. */ + if (settings->sftp_public_key != NULL) { + + guac_client_log(client, GUAC_LOG_DEBUG, + "Attempting public key import"); + + /* Attempt to read public key */ + if (guac_common_ssh_user_import_public_key(rdp_client->sftp_user, + settings->sftp_public_key)) { + + /* Public key import fails. */ + guac_client_abort(client, + GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "Failed to import public key: %s", + guac_common_ssh_key_error()); + + guac_common_ssh_destroy_user(rdp_client->sftp_user); + return NULL; + + } + + /* Success */ + guac_client_log(client, GUAC_LOG_INFO, + "Public key successfully imported."); + + } + } /* Otherwise, use specified password */ @@ -815,8 +843,8 @@ void* guac_rdp_client_thread(void* data) { /* Attempt SSH connection */ rdp_client->sftp_session = guac_common_ssh_create_session(client, settings->sftp_hostname, - settings->sftp_port, rdp_client->sftp_user, settings->sftp_server_alive_interval, - settings->sftp_host_key, NULL); + settings->sftp_port, rdp_client->sftp_user, settings->sftp_timeout, + settings->sftp_server_alive_interval, settings->sftp_host_key, NULL); /* Fail if SSH connection does not succeed */ if (rdp_client->sftp_session == NULL) { diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index 0737f043..4c62b9e2 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -56,6 +56,7 @@ const char fips_nla_mode_warning[] = ( const char* GUAC_RDP_CLIENT_ARGS[] = { "hostname", "port", + "timeout", GUAC_RDP_ARGV_DOMAIN, GUAC_RDP_ARGV_USERNAME, GUAC_RDP_ARGV_PASSWORD, @@ -105,10 +106,12 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { "sftp-hostname", "sftp-host-key", "sftp-port", + "sftp-timeout", "sftp-username", "sftp-password", "sftp-private-key", "sftp-passphrase", + "sftp-public-key", "sftp-directory", "sftp-root-directory", "sftp-server-alive-interval", @@ -164,6 +167,11 @@ enum RDP_ARGS_IDX { */ IDX_PORT, + /** + * The amount of time to wait for the server to respond, in seconds. + */ + IDX_TIMEOUT, + /** * The domain of the user logging in. */ @@ -455,6 +463,12 @@ enum RDP_ARGS_IDX { */ IDX_SFTP_PORT, + /** + * The number of seconds to attempt to connect to the SSH server before + * timing out. + */ + IDX_SFTP_TIMEOUT, + /** * The username to provide when authenticating with the SSH server for * SFTP. If blank, the username provided for the RDP user will be used. @@ -479,6 +493,12 @@ enum RDP_ARGS_IDX { */ IDX_SFTP_PASSPHRASE, + /** + * The base64-encoded public key to use when authenticating with the SSH + * server for SFTP. + */ + IDX_SFTP_PUBLIC_KEY, + /** * The default location for file uploads within the SSH server. This will * apply only to uploads which do not use the filesystem guac_object (where @@ -816,6 +836,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv, IDX_PORT, settings->security_mode == GUAC_SECURITY_VMCONNECT ? RDP_DEFAULT_VMCONNECT_PORT : RDP_DEFAULT_PORT); + /* Look for timeout settings and parse or set defaults. */ + settings->timeout = + guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_TIMEOUT, RDP_DEFAULT_TIMEOUT); + guac_user_log(user, GUAC_LOG_DEBUG, "User resolution is %ix%i at %i DPI", user->info.optimal_width, @@ -1087,6 +1112,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, IDX_SFTP_PORT, "22"); + /* SFTP timeout */ + settings->sftp_timeout = + guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_SFTP_TIMEOUT, RDP_DEFAULT_SFTP_TIMEOUT); + /* Username for SSH/SFTP authentication */ settings->sftp_username = guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, @@ -1103,11 +1133,16 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, IDX_SFTP_PRIVATE_KEY, NULL); - /* Passphrase for decrypting the SFTP private key (if applicable */ + /* Passphrase for decrypting the SFTP private key (if applicable) */ settings->sftp_passphrase = guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, IDX_SFTP_PASSPHRASE, ""); + /* Public key for authenticating to SFTP server, if applicable. */ + settings->sftp_public_key = + guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_SFTP_PUBLIC_KEY, NULL); + /* Default upload directory */ settings->sftp_directory = guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, @@ -1374,6 +1409,7 @@ void guac_rdp_settings_free(guac_rdp_settings* settings) { guac_mem_free(settings->sftp_password); guac_mem_free(settings->sftp_port); guac_mem_free(settings->sftp_private_key); + guac_mem_free(settings->sftp_public_key); guac_mem_free(settings->sftp_username); #endif @@ -1721,6 +1757,7 @@ void guac_rdp_push_settings(guac_client* client, /* Connection */ rdp_settings->ServerHostname = guac_strdup(guac_settings->hostname); rdp_settings->ServerPort = guac_settings->port; + rdp_settings->TcpAckTimeout = guac_settings->timeout * 1000; /* Session */ rdp_settings->ColorDepth = guac_settings->color_depth; diff --git a/src/protocols/rdp/settings.h b/src/protocols/rdp/settings.h index 7837e6ae..253b7628 100644 --- a/src/protocols/rdp/settings.h +++ b/src/protocols/rdp/settings.h @@ -33,11 +33,21 @@ */ #define RDP_CLIENT_HOSTNAME_SIZE 32 +/** + * The default server response timeout, in seconds. + */ +#define RDP_DEFAULT_TIMEOUT 10 + /** * The default RDP port. */ #define RDP_DEFAULT_PORT 3389 +/** + * The default SFTP connection timeout, in seconds. + */ +#define RDP_DEFAULT_SFTP_TIMEOUT 10 + /** * The default RDP port used by Hyper-V "VMConnect". */ @@ -156,6 +166,11 @@ typedef struct guac_rdp_settings { */ int port; + /** + * The timeout, in seconds, to wait for the remote host to respond. + */ + int timeout; + /** * The domain of the user logging in. */ @@ -452,6 +467,12 @@ typedef struct guac_rdp_settings { */ char* sftp_port; + /** + * The number of seconds to attempt to connect to the SSH server before + * timing out. + */ + int sftp_timeout; + /** * The username to provide when authenticating with the SSH server for * SFTP. @@ -476,6 +497,11 @@ typedef struct guac_rdp_settings { */ char* sftp_passphrase; + /** + * The public key to use when connecting to the SFTP server, if applicable. + */ + char* sftp_public_key; + /** * The default location for file uploads within the SSH server. This will * apply only to uploads which do not use the filesystem guac_object (where diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index a297963b..48e7383b 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -38,6 +38,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = { "hostname", "host-key", "port", + "timeout", "username", "password", GUAC_SSH_ARGV_FONT_NAME, @@ -99,6 +100,11 @@ enum SSH_ARGS_IDX { */ IDX_PORT, + /** + * The timeout of the connection attempt, in seconds. Optional. + */ + IDX_TIMEOUT, + /** * The name of the user to login as. Optional. */ @@ -454,6 +460,11 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, IDX_PORT, GUAC_SSH_DEFAULT_PORT); + /* Parse the timeout value. */ + settings->timeout = + guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv, + IDX_TIMEOUT, GUAC_SSH_DEFAULT_TIMEOUT); + /* Read-only mode */ settings->read_only = guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv, diff --git a/src/protocols/ssh/settings.h b/src/protocols/ssh/settings.h index 0f966832..65404618 100644 --- a/src/protocols/ssh/settings.h +++ b/src/protocols/ssh/settings.h @@ -32,6 +32,12 @@ */ #define GUAC_SSH_DEFAULT_PORT "22" +/** + * The default number of seconds to attempt a connection to the SSH/SFTP + * server before giving up. + */ +#define GUAC_SSH_DEFAULT_TIMEOUT 10 + /** * The filename to use for the typescript, if not specified. */ @@ -69,6 +75,12 @@ typedef struct guac_ssh_settings { */ char* port; + /** + * The number of seconds to attempt to connect to the SSH server before + * timing out. + */ + int timeout; + /** * The name of the user to login as, if any. If no username is specified, * this will be NULL. diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 8db094af..199064de 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -134,33 +134,34 @@ static guac_common_ssh_user* guac_ssh_get_user(guac_client* client) { guac_client_log(client, GUAC_LOG_INFO, "Auth key successfully imported."); - } /* end if key given */ + /* Import public key, if available. */ + if (settings->public_key_base64 != NULL) { - if (settings->public_key_base64 != NULL) { + guac_client_log(client, GUAC_LOG_DEBUG, + "Attempting public key import"); - guac_client_log(client, GUAC_LOG_DEBUG, - "Attempting public key import"); + /* Attempt to read public key */ + if (guac_common_ssh_user_import_public_key(user, + settings->public_key_base64)) { - /* Attempt to read public key */ - if (guac_common_ssh_user_import_public_key(user, - settings->public_key_base64)) { + /* Public key import fails. */ + guac_client_abort(client, + GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "Auth public key import failed: %s", + guac_common_ssh_key_error()); - /* If failing*/ - guac_client_abort(client, - GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, - "Auth public key import failed: %s", - guac_common_ssh_key_error()); + guac_common_ssh_destroy_user(user); + return NULL; - guac_common_ssh_destroy_user(user); - return NULL; + } + + /* Success */ + guac_client_log(client, GUAC_LOG_INFO, + "Auth public key successfully imported."); } - /* Success */ - guac_client_log(client, GUAC_LOG_INFO, - "Auth public key successfully imported."); - - } + } /* end if key given */ /* If available, get password from settings */ else if (settings->password != NULL) { @@ -250,7 +251,8 @@ void* ssh_client_thread(void* data) { settings->wol_wait_time, GUAC_WOL_DEFAULT_CONNECT_RETRIES, settings->hostname, - settings->port)) { + settings->port, + settings->timeout)) { guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet or connect to remote server."); return NULL; } @@ -336,7 +338,8 @@ void* ssh_client_thread(void* data) { /* Open SSH session */ 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->timeout, settings->server_alive_interval, settings->host_key, guac_ssh_get_credential); if (ssh_client->session == NULL) { /* Already aborted within guac_common_ssh_create_session() */ @@ -387,8 +390,8 @@ void* ssh_client_thread(void* data) { guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP..."); ssh_client->sftp_session = guac_common_ssh_create_session(client, settings->hostname, - settings->port, ssh_client->user, settings->server_alive_interval, - settings->host_key, NULL); + settings->port, ssh_client->user, settings->timeout, + settings->server_alive_interval, settings->host_key, NULL); if (ssh_client->sftp_session == NULL) { /* Already aborted within guac_common_ssh_create_session() */ return NULL; diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c index 80ce6c87..a524e693 100644 --- a/src/protocols/telnet/telnet.c +++ b/src/protocols/telnet/telnet.c @@ -386,7 +386,7 @@ static telnet_t* __guac_telnet_create_session(guac_client* client) { guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; guac_telnet_settings* settings = telnet_client->settings; - int fd = guac_socket_tcp_connect(settings->hostname, settings->port); + int fd = guac_socket_tcp_connect(settings->hostname, settings->port, settings->timeout); /* Open telnet session */ telnet_t* telnet = telnet_init(__telnet_options, __guac_telnet_event_handler, 0, client); @@ -511,7 +511,8 @@ void* guac_telnet_client_thread(void* data) { settings->wol_wait_time, GUAC_WOL_DEFAULT_CONNECT_RETRIES, settings->hostname, - settings->port)) { + settings->port, + settings->timeout)) { guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet or connect to remote server."); return NULL; } diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c index c7dda589..5b7df0ba 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -68,10 +68,12 @@ const char* GUAC_VNC_CLIENT_ARGS[] = { "sftp-hostname", "sftp-host-key", "sftp-port", + "sftp-timeout", "sftp-username", "sftp-password", "sftp-private-key", "sftp-passphrase", + "sftp-public-key", "sftp-directory", "sftp-root-directory", "sftp-server-alive-interval", @@ -241,6 +243,12 @@ enum VNC_ARGS_IDX { */ IDX_SFTP_PORT, + /** + * The number of seconds to attempt to connect to the SFTP server before + * timing out. + */ + IDX_SFTP_TIMEOUT, + /** * The username to provide when authenticating with the SSH server for * SFTP. @@ -265,6 +273,12 @@ enum VNC_ARGS_IDX { */ IDX_SFTP_PASSPHRASE, + /** + * The base64-encode public key to use when authentication with the SSH + * server for SFTP using key-based authentication. + */ + IDX_SFTP_PUBLIC_KEY, + /** * The default location for file uploads within the SSH server. This will * apply only to uploads which do not use the filesystem guac_object (where @@ -576,6 +590,11 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user, guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, IDX_SFTP_PORT, "22"); + /* SFTP connection timeout */ + settings->sftp_timeout = + guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, + IDX_SFTP_TIMEOUT, GUAC_VNC_DEFAULT_SFTP_TIMEOUT); + /* Username for SSH/SFTP authentication */ settings->sftp_username = guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, @@ -596,6 +615,11 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user, guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, IDX_SFTP_PASSPHRASE, ""); + /* Public key for SFTP using key-based authentication. */ + settings->sftp_public_key = + guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, + IDX_SFTP_PUBLIC_KEY, NULL); + /* Default upload directory */ settings->sftp_directory = guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, @@ -731,6 +755,7 @@ void guac_vnc_settings_free(guac_vnc_settings* settings) { guac_mem_free(settings->sftp_password); guac_mem_free(settings->sftp_port); guac_mem_free(settings->sftp_private_key); + guac_mem_free(settings->sftp_public_key); guac_mem_free(settings->sftp_username); #endif diff --git a/src/protocols/vnc/settings.h b/src/protocols/vnc/settings.h index e5c3b779..f433df9b 100644 --- a/src/protocols/vnc/settings.h +++ b/src/protocols/vnc/settings.h @@ -29,6 +29,11 @@ */ #define GUAC_VNC_DEFAULT_RECORDING_NAME "recording" +/** + * The default number of seconds to attempt to connect to the SFTP server. + */ +#define GUAC_VNC_DEFAULT_SFTP_TIMEOUT 10 + /** * VNC-specific client data. */ @@ -188,6 +193,11 @@ typedef struct guac_vnc_settings { */ char* sftp_port; + /** + * The number of seconds to attempt to connect to the SFTP server. + */ + int sftp_timeout; + /** * The username to provide when authenticating with the SSH server for * SFTP. @@ -212,6 +222,12 @@ typedef struct guac_vnc_settings { */ char* sftp_passphrase; + /** + * The base64-encoded public key to use when authenticating with the SSH + * server for SFTP using key-based authentication. + */ + char* sftp_public_key; + /** * The default location for file uploads within the SSH server. This will * apply only to uploads which do not use the filesystem guac_object (where diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index 9ed93fdf..d244dcb9 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -301,7 +301,8 @@ void* guac_vnc_client_thread(void* data) { settings->wol_wait_time, GUAC_WOL_DEFAULT_CONNECT_RETRIES, settings->hostname, - (const char *) str_port)) { + (const char *) str_port, + GUAC_WOL_DEFAULT_CONNECTION_TIMEOUT)) { guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet or connect to remote system."); guac_mem_free(str_port); return NULL; @@ -396,6 +397,33 @@ void* guac_vnc_client_thread(void* data) { return NULL; } + /* Import the public key, if that is specified. */ + if (settings->sftp_public_key != NULL) { + + guac_client_log(client, GUAC_LOG_DEBUG, + "Attempting public key import"); + + /* Attempt to read public key */ + if (guac_common_ssh_user_import_public_key(vnc_client->sftp_user, + settings->sftp_public_key)) { + + /* Public key import fails. */ + guac_client_abort(client, + GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "Failed to import public key: %s", + guac_common_ssh_key_error()); + + guac_common_ssh_destroy_user(vnc_client->sftp_user); + return NULL; + + } + + /* Success */ + guac_client_log(client, GUAC_LOG_INFO, + "Public key successfully imported."); + + } + } /* Otherwise, use specified password */ @@ -409,8 +437,8 @@ void* guac_vnc_client_thread(void* data) { /* Attempt SSH connection */ vnc_client->sftp_session = guac_common_ssh_create_session(client, settings->sftp_hostname, - settings->sftp_port, vnc_client->sftp_user, settings->sftp_server_alive_interval, - settings->sftp_host_key, NULL); + settings->sftp_port, vnc_client->sftp_user, settings->sftp_timeout, + settings->sftp_server_alive_interval, settings->sftp_host_key, NULL); /* Fail if SSH connection does not succeed */ if (vnc_client->sftp_session == NULL) {