From ca0fc75f9b7b65d4f8e0e3db73fdc73381f2c0d6 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Wed, 15 Feb 2023 14:55:16 -0500 Subject: [PATCH 1/6] GUACAMOLE-600: Add support for setting the FreeRDP TcpAckTimeout setting. --- src/protocols/rdp/settings.c | 12 ++++++++++++ src/protocols/rdp/settings.h | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index f2dbeabd..55a87434 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -54,6 +54,7 @@ const char fips_nla_mode_warning[] = ( const char* GUAC_RDP_CLIENT_ARGS[] = { "hostname", "port", + "server-timeout", GUAC_RDP_ARGV_DOMAIN, GUAC_RDP_ARGV_USERNAME, GUAC_RDP_ARGV_PASSWORD, @@ -159,6 +160,11 @@ enum RDP_ARGS_IDX { */ IDX_PORT, + /** + * The amount of time to wait for the server to respond, in seconds. + */ + IDX_SERVER_TIMEOUT, + /** * The domain of the user logging in. */ @@ -780,6 +786,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->server_timeout = + guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_SERVER_TIMEOUT, RDP_DEFAULT_SERVER_TIMEOUT); + guac_user_log(user, GUAC_LOG_DEBUG, "User resolution is %ix%i at %i DPI", user->info.optimal_width, @@ -1424,6 +1435,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->server_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 3fe9d002..749d0ddd 100644 --- a/src/protocols/rdp/settings.h +++ b/src/protocols/rdp/settings.h @@ -33,6 +33,11 @@ */ #define RDP_CLIENT_HOSTNAME_SIZE 32 +/** + * The default server response timeout, in seconds. + */ +#define RDP_DEFAULT_SERVER_TIMEOUT 10 + /** * The default RDP port. */ @@ -156,6 +161,11 @@ typedef struct guac_rdp_settings { */ int port; + /** + * The timeout, in seconds, to wait for the remote host to respond. + */ + int server_timeout; + /** * The domain of the user logging in. */ From 1cdda6dd2c8d2fcc48b138298b651241d06a9865 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Thu, 16 Feb 2023 16:52:23 -0500 Subject: [PATCH 2/6] GUACAMOLE-600: Add support for setting SSH and SFTP timeouts. --- src/common-ssh/common-ssh/ssh.h | 6 +++++- src/common-ssh/ssh.c | 10 +++++++-- src/libguac/guacamole/socket-tcp.h | 5 ++++- src/libguac/guacamole/wol-constants.h | 6 ++++++ src/libguac/guacamole/wol.h | 6 +++++- src/libguac/socket-tcp.c | 30 +++++++++++++++++++++------ src/libguac/wol.c | 6 +++--- src/protocols/rdp/rdp.c | 7 ++++--- src/protocols/rdp/settings.c | 12 +++++++++++ src/protocols/rdp/settings.h | 11 ++++++++++ src/protocols/ssh/settings.c | 11 ++++++++++ src/protocols/ssh/settings.h | 12 +++++++++++ src/protocols/ssh/ssh.c | 10 +++++---- src/protocols/vnc/settings.c | 12 +++++++++++ src/protocols/vnc/settings.h | 10 +++++++++ src/protocols/vnc/vnc.c | 7 ++++--- 16 files changed, 137 insertions(+), 24 deletions(-) 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 c669dc47..5629c0bf 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) { @@ -222,7 +222,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 d2e5bf96..b2c3c3a1 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -725,7 +725,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; @@ -823,8 +824,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 4b02b3eb..6e12fb30 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -104,6 +104,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { "sftp-hostname", "sftp-host-key", "sftp-port", + "sftp-timeout", "sftp-username", "sftp-password", "sftp-private-key", @@ -454,6 +455,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. @@ -1086,6 +1093,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, diff --git a/src/protocols/rdp/settings.h b/src/protocols/rdp/settings.h index 7837e6ae..de839544 100644 --- a/src/protocols/rdp/settings.h +++ b/src/protocols/rdp/settings.h @@ -38,6 +38,11 @@ */ #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". */ @@ -452,6 +457,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. 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..5a0a7e74 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -250,7 +250,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 +337,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 +389,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/vnc/settings.c b/src/protocols/vnc/settings.c index 09ee8a7a..a441e5d2 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -67,6 +67,7 @@ const char* GUAC_VNC_CLIENT_ARGS[] = { "sftp-hostname", "sftp-host-key", "sftp-port", + "sftp-timeout", "sftp-username", "sftp-password", "sftp-private-key", @@ -233,6 +234,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. @@ -563,6 +570,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, diff --git a/src/protocols/vnc/settings.h b/src/protocols/vnc/settings.h index 3b885816..ef855093 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. */ @@ -182,6 +187,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. diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index ec2c505d..6076e591 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; @@ -409,8 +410,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) { From 7d0b76be639bec30a0d17e11f01086597f577b20 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Fri, 24 May 2024 21:33:04 -0400 Subject: [PATCH 3/6] GUACAMOLE-600: Update telnet protocol to send timeout to common socket code. --- src/protocols/telnet/telnet.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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; } From 049f5f7c0c326879ed68366029d6b85c08727da8 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 26 Aug 2024 15:47:17 -0400 Subject: [PATCH 4/6] GUACAMOLE-600: Name RDP timeout setting consistent with other protocols. --- src/protocols/rdp/settings.c | 10 +++++----- src/protocols/rdp/settings.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index 548345cc..3edd11c5 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -56,7 +56,7 @@ const char fips_nla_mode_warning[] = ( const char* GUAC_RDP_CLIENT_ARGS[] = { "hostname", "port", - "server-timeout", + "timeout", GUAC_RDP_ARGV_DOMAIN, GUAC_RDP_ARGV_USERNAME, GUAC_RDP_ARGV_PASSWORD, @@ -169,7 +169,7 @@ enum RDP_ARGS_IDX { /** * The amount of time to wait for the server to respond, in seconds. */ - IDX_SERVER_TIMEOUT, + IDX_TIMEOUT, /** * The domain of the user logging in. @@ -830,9 +830,9 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, settings->security_mode == GUAC_SECURITY_VMCONNECT ? RDP_DEFAULT_VMCONNECT_PORT : RDP_DEFAULT_PORT); /* Look for timeout settings and parse or set defaults. */ - settings->server_timeout = + settings->timeout = guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv, - IDX_SERVER_TIMEOUT, RDP_DEFAULT_SERVER_TIMEOUT); + IDX_TIMEOUT, RDP_DEFAULT_TIMEOUT); guac_user_log(user, GUAC_LOG_DEBUG, "User resolution is %ix%i at %i DPI", @@ -1744,7 +1744,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->server_timeout * 1000; + 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 cedbee95..330fc763 100644 --- a/src/protocols/rdp/settings.h +++ b/src/protocols/rdp/settings.h @@ -36,7 +36,7 @@ /** * The default server response timeout, in seconds. */ -#define RDP_DEFAULT_SERVER_TIMEOUT 10 +#define RDP_DEFAULT_TIMEOUT 10 /** * The default RDP port. @@ -169,7 +169,7 @@ typedef struct guac_rdp_settings { /** * The timeout, in seconds, to wait for the remote host to respond. */ - int server_timeout; + int timeout; /** * The domain of the user logging in. From 9f6958accf6e67a5a71a706443829a3aa328378f Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 26 Aug 2024 16:26:07 -0400 Subject: [PATCH 5/6] GUACAMOLE-1290: Add public key parameter for SFTP connections in RDP and VNC protocols. --- src/protocols/rdp/rdp.c | 27 +++++++++++++++++++++++++++ src/protocols/rdp/settings.c | 15 ++++++++++++++- src/protocols/rdp/settings.h | 5 +++++ src/protocols/vnc/settings.c | 13 +++++++++++++ src/protocols/vnc/settings.h | 6 ++++++ src/protocols/vnc/vnc.c | 27 +++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index b29c7c63..4cf8e5f4 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -800,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 */ diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index 548345cc..d8567a73 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -111,6 +111,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { "sftp-password", "sftp-private-key", "sftp-passphrase", + "sftp-public-key", "sftp-directory", "sftp-root-directory", "sftp-server-alive-interval", @@ -492,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 @@ -1126,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, @@ -1397,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 diff --git a/src/protocols/rdp/settings.h b/src/protocols/rdp/settings.h index cedbee95..2f4d6ef9 100644 --- a/src/protocols/rdp/settings.h +++ b/src/protocols/rdp/settings.h @@ -497,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/vnc/settings.c b/src/protocols/vnc/settings.c index bfdcbf82..5b7df0ba 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -73,6 +73,7 @@ const char* GUAC_VNC_CLIENT_ARGS[] = { "sftp-password", "sftp-private-key", "sftp-passphrase", + "sftp-public-key", "sftp-directory", "sftp-root-directory", "sftp-server-alive-interval", @@ -272,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 @@ -608,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, @@ -743,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 9b27463b..f433df9b 100644 --- a/src/protocols/vnc/settings.h +++ b/src/protocols/vnc/settings.h @@ -222,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 517237da..d244dcb9 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -397,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 */ From 5e0ce1db8fe7c0c761c62f42b7cea0b0f3c9608c Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 26 Aug 2024 16:28:32 -0400 Subject: [PATCH 6/6] GUACAMOLE-1290: Move public key import in SSH connection code. --- src/protocols/ssh/ssh.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 5a0a7e74..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) {