GUACAMOLE-326: Merge rejection of reads and writes to Windows data streams.

This commit is contained in:
James Muehlner 2017-06-26 21:05:03 -07:00
commit 836fc3eaa0
18 changed files with 112 additions and 14 deletions

View File

@ -18,7 +18,7 @@
# #
AC_PREREQ([2.61]) AC_PREREQ([2.61])
AC_INIT([guacamole-server], [0.9.12-incubating]) AC_INIT([guacamole-server], [0.9.13-incubating])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])

View File

@ -22,7 +22,7 @@
# #
PROJECT_NAME = libguac PROJECT_NAME = libguac
PROJECT_NUMBER = 0.9.12-incubating PROJECT_NUMBER = 0.9.13-incubating
# #
# Warn about undocumented parameters and return values, but do not fill output # Warn about undocumented parameters and return values, but do not fill output

View File

@ -98,7 +98,7 @@ void guac_common_ssh_uninit();
* if the connection or authentication were not successful. * if the connection or authentication were not successful.
*/ */
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
const char* hostname, const char* port, guac_common_ssh_user* user); const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive);
/** /**
* Disconnects and destroys the given SSH session, freeing all associated * Disconnects and destroys the given SSH session, freeing all associated

View File

@ -414,7 +414,7 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
} }
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
const char* hostname, const char* port, guac_common_ssh_user* user) { const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive) {
int retval; int retval;
@ -532,6 +532,20 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
return NULL; return NULL;
} }
/* Warn if keepalive below minimum value */
if (keepalive < 0) {
keepalive = 0;
guac_client_log(client, GUAC_LOG_WARNING, "negative keepalive intervals "
"are converted to 0, disabling keepalive.");
}
else if (keepalive == 1) {
guac_client_log(client, GUAC_LOG_WARNING, "keepalive interval will "
"be rounded up to minimum value of 2.");
}
/* Configure session keepalive */
libssh2_keepalive_config(common_session->session, 1, keepalive);
/* Return created session */ /* Return created session */
return common_session; return common_session;

View File

@ -16,7 +16,7 @@
.\" specific language governing permissions and limitations .\" specific language governing permissions and limitations
.\" under the License. .\" under the License.
.\" .\"
.TH guacd 8 "9 Jan 2017" "version 0.9.11-incubating" "Guacamole" .TH guacd 8 "1 Jun 2017" "version 0.9.13-incubating" "Guacamole"
. .
.SH NAME .SH NAME
guacd \- Guacamole proxy daemon guacd \- Guacamole proxy daemon

View File

@ -16,7 +16,7 @@
.\" specific language governing permissions and limitations .\" specific language governing permissions and limitations
.\" under the License. .\" under the License.
.\" .\"
.TH guacd.conf 5 "9 Jan 2017" "version 0.9.11-incubating" "Guacamole" .TH guacd.conf 5 "1 Jun 2017" "version 0.9.13-incubating" "Guacamole"
. .
.SH NAME .SH NAME
/etc/guacamole/guacd.conf \- Configuration file for guacd /etc/guacamole/guacd.conf \- Configuration file for guacd

View File

@ -16,7 +16,7 @@
.\" specific language governing permissions and limitations .\" specific language governing permissions and limitations
.\" under the License. .\" under the License.
.\" .\"
.TH guacenc 1 "9 Jan 2017" "version 0.9.11-incubating" "Guacamole" .TH guacenc 1 "1 Jun 2017" "version 0.9.13-incubating" "Guacamole"
. .
.SH NAME .SH NAME
guacenc \- Guacamole video encoder guacenc \- Guacamole video encoder

View File

@ -104,7 +104,7 @@ libguac_la_CFLAGS = \
-Werror -Wall -pedantic -Iguacamole -Werror -Wall -pedantic -Iguacamole
libguac_la_LDFLAGS = \ libguac_la_LDFLAGS = \
-version-info 13:0:1 \ -version-info 14:0:2 \
@CAIRO_LIBS@ \ @CAIRO_LIBS@ \
@JPEG_LIBS@ \ @JPEG_LIBS@ \
@PNG_LIBS@ \ @PNG_LIBS@ \

View File

@ -977,7 +977,7 @@ void* guac_rdp_client_thread(void* data) {
/* Attempt SSH connection */ /* Attempt SSH connection */
rdp_client->sftp_session = rdp_client->sftp_session =
guac_common_ssh_create_session(client, settings->sftp_hostname, guac_common_ssh_create_session(client, settings->sftp_hostname,
settings->sftp_port, rdp_client->sftp_user); settings->sftp_port, rdp_client->sftp_user, settings->sftp_server_alive_interval);
/* Fail if SSH connection does not succeed */ /* Fail if SSH connection does not succeed */
if (rdp_client->sftp_session == NULL) { if (rdp_client->sftp_session == NULL) {

View File

@ -654,6 +654,10 @@ int guac_rdp_fs_normalize_path(const char* path, char* abs_path) {
} /* end if separator */ } /* end if separator */
/* We do not currently support named streams */
else if (c == ':')
return 1;
} /* end for each character */ } /* end for each character */
/* If no components, the path is simply root */ /* If no components, the path is simply root */

View File

@ -84,6 +84,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
"sftp-private-key", "sftp-private-key",
"sftp-passphrase", "sftp-passphrase",
"sftp-directory", "sftp-directory",
"sftp-server-alive-interval",
#endif #endif
"recording-path", "recording-path",
@ -366,6 +367,13 @@ enum RDP_ARGS_IDX {
*/ */
IDX_SFTP_DIRECTORY, IDX_SFTP_DIRECTORY,
/**
* The interval at which SSH keepalive messages are sent to the server for
* SFTP connections. The default is 0 (disabling keepalives), and a value
* of 1 is automatically increased to 2 by libssh2 to avoid busy loop corner
* cases.
*/
IDX_SFTP_SERVER_ALIVE_INTERVAL,
#endif #endif
/** /**
@ -775,6 +783,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
settings->sftp_directory = settings->sftp_directory =
guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
IDX_SFTP_DIRECTORY, NULL); IDX_SFTP_DIRECTORY, NULL);
/* Default keepalive value */
settings->sftp_server_alive_interval =
guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
IDX_SFTP_SERVER_ALIVE_INTERVAL, 0);
#endif #endif
/* Read recording path */ /* Read recording path */

View File

@ -359,6 +359,14 @@ typedef struct guac_rdp_settings {
* the destination directory is otherwise ambiguous). * the destination directory is otherwise ambiguous).
*/ */
char* sftp_directory; char* sftp_directory;
/**
* The interval at which SSH keepalive messages are sent to the server for
* SFTP connections. The default is 0 (disabling keepalives), and a value
* of 1 is automatically increased to 2 by libssh2 to avoid busy loop corner
* cases.
*/
int sftp_server_alive_interval;
#endif #endif
/** /**

View File

@ -51,6 +51,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = {
"recording-name", "recording-name",
"create-recording-path", "create-recording-path",
"read-only", "read-only",
"server-alive-interval",
NULL NULL
}; };
@ -165,6 +166,13 @@ enum SSH_ARGS_IDX {
*/ */
IDX_READ_ONLY, IDX_READ_ONLY,
/**
* Number of seconds between sending alive packets. A default of 0
* tells SSH not to send these packets. A value of 1 is automatically
* changed by libssh2 to 2 to avoid busy-loop corner cases.
*/
IDX_SERVER_ALIVE_INTERVAL,
SSH_ARGS_COUNT SSH_ARGS_COUNT
}; };
@ -279,6 +287,11 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv, guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_CREATE_RECORDING_PATH, false); IDX_CREATE_RECORDING_PATH, false);
/* Parse server alive interval */
settings->server_alive_interval =
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_SERVER_ALIVE_INTERVAL, 0);
/* Parsing was successful */ /* Parsing was successful */
return settings; return settings;

View File

@ -53,6 +53,11 @@
*/ */
#define GUAC_SSH_DEFAULT_RECORDING_NAME "recording" #define GUAC_SSH_DEFAULT_RECORDING_NAME "recording"
/**
* The default polling timeout for SSH activity in milliseconds.
*/
#define GUAC_SSH_DEFAULT_POLL_TIMEOUT 1000
/** /**
* Settings for the SSH connection. The values for this structure are parsed * Settings for the SSH connection. The values for this structure are parsed
* from the arguments given during the Guacamole protocol handshake using the * from the arguments given during the Guacamole protocol handshake using the
@ -181,6 +186,11 @@ typedef struct guac_ssh_settings {
*/ */
bool create_recording_path; bool create_recording_path;
/**
* The number of seconds between sending server alive messages.
*/
int server_alive_interval;
} guac_ssh_settings; } guac_ssh_settings;
/** /**

View File

@ -218,7 +218,7 @@ void* ssh_client_thread(void* data) {
/* 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->hostname, settings->port, ssh_client->user, settings->server_alive_interval);
if (ssh_client->session == NULL) { if (ssh_client->session == NULL) {
/* Already aborted within guac_common_ssh_create_session() */ /* Already aborted within guac_common_ssh_create_session() */
return NULL; return NULL;
@ -258,7 +258,7 @@ void* ssh_client_thread(void* data) {
guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP..."); guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP...");
ssh_client->sftp_session = ssh_client->sftp_session =
guac_common_ssh_create_session(client, settings->hostname, guac_common_ssh_create_session(client, settings->hostname,
settings->port, ssh_client->user); settings->port, ssh_client->user, settings->server_alive_interval);
if (ssh_client->sftp_session == NULL) { if (ssh_client->sftp_session == NULL) {
/* Already aborted within guac_common_ssh_create_session() */ /* Already aborted within guac_common_ssh_create_session() */
return NULL; return NULL;
@ -323,6 +323,9 @@ void* ssh_client_thread(void* data) {
/* Track total amount of data read */ /* Track total amount of data read */
int total_read = 0; int total_read = 0;
/* Timeout for polling socket activity */
int timeout;
pthread_mutex_lock(&(ssh_client->term_channel_lock)); pthread_mutex_lock(&(ssh_client->term_channel_lock));
/* Stop reading at EOF */ /* Stop reading at EOF */
@ -331,6 +334,17 @@ void* ssh_client_thread(void* data) {
break; break;
} }
/* Send keepalive at configured interval */
if (settings->server_alive_interval > 0) {
timeout = 0;
if (libssh2_keepalive_send(ssh_client->session->session, &timeout) > 0)
break;
timeout *= 1000;
}
/* If keepalive is not configured, sleep for the default of 1 second */
else
timeout = GUAC_SSH_DEFAULT_POLL_TIMEOUT;
/* Read terminal data */ /* Read terminal data */
bytes_read = libssh2_channel_read(ssh_client->term_channel, bytes_read = libssh2_channel_read(ssh_client->term_channel,
buffer, sizeof(buffer)); buffer, sizeof(buffer));
@ -370,8 +384,8 @@ void* ssh_client_thread(void* data) {
.revents = 0, .revents = 0,
}}; }};
/* Wait up to one second */ /* Wait up to computed timeout */
if (poll(fds, 1, 1000) < 0) if (poll(fds, 1, timeout) < 0)
break; break;
} }

View File

@ -66,6 +66,7 @@ const char* GUAC_VNC_CLIENT_ARGS[] = {
"sftp-private-key", "sftp-private-key",
"sftp-passphrase", "sftp-passphrase",
"sftp-directory", "sftp-directory",
"sftp-server-alive-interval",
#endif #endif
"recording-path", "recording-path",
@ -227,6 +228,14 @@ enum VNC_ARGS_IDX {
* the destination directory is otherwise ambiguous). * the destination directory is otherwise ambiguous).
*/ */
IDX_SFTP_DIRECTORY, IDX_SFTP_DIRECTORY,
/**
* The interval at which SSH keepalive messages are sent to the server for
* SFTP connections. The default is 0 (disabling keepalives), and a value
* of 1 is automatically incremented to 2 by libssh2 to avoid busy loop corner
* cases.
*/
IDX_SFTP_SERVER_ALIVE_INTERVAL,
#endif #endif
/** /**
@ -395,6 +404,11 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user,
settings->sftp_directory = settings->sftp_directory =
guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
IDX_SFTP_DIRECTORY, NULL); IDX_SFTP_DIRECTORY, NULL);
/* Default keepalive value */
settings->sftp_server_alive_interval =
guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv,
IDX_SFTP_SERVER_ALIVE_INTERVAL, 0);
#endif #endif
/* Read recording path */ /* Read recording path */

View File

@ -173,6 +173,14 @@ typedef struct guac_vnc_settings {
* the destination directory is otherwise ambiguous). * the destination directory is otherwise ambiguous).
*/ */
char* sftp_directory; char* sftp_directory;
/**
* The interval at which SSH keepalive messages are sent to the server for
* SFTP connections. The default is 0 (disabling keepalives), and a value
* of 1 is automatically increased to 2 by libssh2 to avoid busy loop corner
* cases.
*/
int sftp_server_alive_interval;
#endif #endif
/** /**

View File

@ -261,7 +261,7 @@ void* guac_vnc_client_thread(void* data) {
/* Attempt SSH connection */ /* Attempt SSH connection */
vnc_client->sftp_session = vnc_client->sftp_session =
guac_common_ssh_create_session(client, settings->sftp_hostname, guac_common_ssh_create_session(client, settings->sftp_hostname,
settings->sftp_port, vnc_client->sftp_user); settings->sftp_port, vnc_client->sftp_user, settings->sftp_server_alive_interval);
/* Fail if SSH connection does not succeed */ /* Fail if SSH connection does not succeed */
if (vnc_client->sftp_session == NULL) { if (vnc_client->sftp_session == NULL) {