From 1a699686b9dd7fbcad1eb1c0a6177a80f9313a55 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Thu, 26 Dec 2019 11:25:58 -0500 Subject: [PATCH] GUACAMOLE-474: Implement logic to disable file transfers in each protocol. --- src/common-ssh/common-ssh/sftp.h | 19 ++++++++++++++++- src/common-ssh/sftp.c | 21 ++++++++++++++++--- .../rdp/channels/rdpdr/rdpdr-fs-messages.c | 5 +++-- src/protocols/rdp/fs.c | 12 ++++++++--- src/protocols/rdp/fs.h | 20 +++++++++++++++++- src/protocols/rdp/rdp.c | 7 +++++-- src/protocols/rdp/user.c | 9 ++++---- src/protocols/ssh/settings.c | 2 +- src/protocols/ssh/settings.h | 4 ++-- src/protocols/ssh/ssh.c | 10 ++++++--- src/protocols/ssh/user.c | 2 +- src/protocols/vnc/user.c | 2 +- src/protocols/vnc/vnc.c | 4 +++- 13 files changed, 92 insertions(+), 25 deletions(-) diff --git a/src/common-ssh/common-ssh/sftp.h b/src/common-ssh/common-ssh/sftp.h index eafdf21f..a3784ea2 100644 --- a/src/common-ssh/common-ssh/sftp.h +++ b/src/common-ssh/common-ssh/sftp.h @@ -69,6 +69,16 @@ typedef struct guac_common_ssh_sftp_filesystem { * instruction. */ char upload_path[GUAC_COMMON_SSH_SFTP_MAX_PATH]; + + /** + * If downloads from SFTP to the local browser should be disabled. + */ + int disable_download; + + /** + * If uploads from the local browser to SFTP should be disabled. + */ + int disable_upload; } guac_common_ssh_sftp_filesystem; @@ -122,13 +132,20 @@ typedef struct guac_common_ssh_sftp_ls_state { * The name to send as the name of the filesystem whenever it is exposed * to a user, or NULL to automatically generate a name from the provided * root_path. + * + * @param disable_download + * Whether downloads from the SFTP share to the local browser should be + * disabled. + * + * @param disable_upload + * Whether uploads from the local browser to SFTP should be disabled. * * @return * A new SFTP filesystem object, not yet exposed to users. */ guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem( guac_common_ssh_session* session, const char* root_path, - const char* name); + const char* name, int disable_download, int disable_upload); /** * Destroys the given filesystem object, disconnecting from SFTP and freeing diff --git a/src/common-ssh/sftp.c b/src/common-ssh/sftp.c index b05409b5..e7d55e56 100644 --- a/src/common-ssh/sftp.c +++ b/src/common-ssh/sftp.c @@ -429,7 +429,7 @@ int guac_common_ssh_sftp_handle_file_stream( /** * Handler for ack messages which continue an outbound SFTP data transfer - * (download), signalling the current status and requesting additional data. + * (download), signaling the current status and requesting additional data. * The data associated with the given stream is expected to be a pointer to an * open LIBSSH2_SFTP_HANDLE for the file from which the data is to be read. * @@ -787,6 +787,13 @@ static int guac_common_ssh_sftp_get_handler(guac_user* user, /* Otherwise, send file contents */ else { + /* If downloads are disabled, log and return. */ + if (filesystem->disable_download) { + guac_user_log(user, GUAC_LOG_INFO, + "File downloads have been disabled."); + return 0; + } + /* Open as normal file */ LIBSSH2_SFTP_HANDLE* file = libssh2_sftp_open(sftp, fullpath, LIBSSH2_FXF_READ, 0); @@ -903,7 +910,11 @@ guac_object* guac_common_ssh_alloc_sftp_filesystem_object( /* Init filesystem */ guac_object* fs_object = guac_user_alloc_object(user); fs_object->get_handler = guac_common_ssh_sftp_get_handler; - fs_object->put_handler = guac_common_ssh_sftp_put_handler; + + /* Only handle uploads if not disabled. */ + if (!filesystem->disable_upload) + fs_object->put_handler = guac_common_ssh_sftp_put_handler; + fs_object->data = filesystem; /* Send filesystem to user */ @@ -916,7 +927,7 @@ guac_object* guac_common_ssh_alloc_sftp_filesystem_object( guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem( guac_common_ssh_session* session, const char* root_path, - const char* name) { + const char* name, int disable_download, int disable_upload) { /* Request SFTP */ LIBSSH2_SFTP* sftp_session = libssh2_sftp_init(session->session); @@ -930,6 +941,10 @@ guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem( /* Associate SSH session with SFTP data and user */ filesystem->ssh_session = session; filesystem->sftp_session = sftp_session; + + /* Copy over disable flags */ + filesystem->disable_download = disable_download; + filesystem->disable_upload = disable_upload; /* Normalize and store the provided root path */ if (!guac_common_ssh_sftp_normalize_path(filesystem->root_path, diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c index 529eea57..6c004948 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c @@ -221,8 +221,9 @@ void guac_rdpdr_fs_process_close(guac_rdp_common_svc* svc, return; /* If file was written to, and it's in the \Download folder, start stream */ - if (file->bytes_written > 0 && - strncmp(file->absolute_path, "\\Download\\", 10) == 0) { + if (file->bytes_written > 0 + && strncmp(file->absolute_path, "\\Download\\", 10) == 0 + && !((guac_rdp_fs*) device->data)->disable_download) { guac_client_for_owner(svc->client, guac_rdp_download_to_user, file->absolute_path); guac_rdp_fs_delete((guac_rdp_fs*) device->data, iorequest->file_id); } diff --git a/src/protocols/rdp/fs.c b/src/protocols/rdp/fs.c index 5223b5a6..937b58af 100644 --- a/src/protocols/rdp/fs.c +++ b/src/protocols/rdp/fs.c @@ -43,7 +43,7 @@ #include guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path, - int create_drive_path) { + int create_drive_path, int disable_download, int disable_upload) { /* Create drive path if it does not exist */ if (create_drive_path) { @@ -65,6 +65,8 @@ guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path, fs->drive_path = strdup(drive_path); fs->file_id_pool = guac_pool_alloc(0); fs->open_files = 0; + fs->disable_download = disable_download; + fs->disable_upload = disable_upload; return fs; @@ -77,11 +79,15 @@ void guac_rdp_fs_free(guac_rdp_fs* fs) { } guac_object* guac_rdp_fs_alloc_object(guac_rdp_fs* fs, guac_user* user) { - + /* Init filesystem */ guac_object* fs_object = guac_user_alloc_object(user); fs_object->get_handler = guac_rdp_download_get_handler; - fs_object->put_handler = guac_rdp_upload_put_handler; + + /* Assign handler only if uploads are not disabled. */ + if(!fs->disable_upload) + fs_object->put_handler = guac_rdp_upload_put_handler; + fs_object->data = fs; /* Send filesystem to user */ diff --git a/src/protocols/rdp/fs.h b/src/protocols/rdp/fs.h index 83a0b3bd..d3782f00 100644 --- a/src/protocols/rdp/fs.h +++ b/src/protocols/rdp/fs.h @@ -219,6 +219,16 @@ typedef struct guac_rdp_fs { * All available file structures. */ guac_rdp_fs_file files[GUAC_RDP_FS_MAX_FILES]; + + /** + * If downloads from the remote server to the browser should be disabled. + */ + int disable_download; + + /** + * If uploads from the browser to the remote server should be disabled. + */ + int disable_upload; } guac_rdp_fs; @@ -258,12 +268,20 @@ typedef struct guac_rdp_fs_info { * @param create_drive_path * Non-zero if the drive path specified should be automatically created if * it does not yet exist, zero otherwise. + * + * @param disable_download + * Non-zero if downloads from the remote server to the local browser should + * be disabled. + * + * @param disable_upload + * Non-zero if uploads from the browser to the remote server should be + * disabled. * * @return * The newly-allocated filesystem. */ guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path, - int create_drive_path); + int create_drive_path, int disable_download, int disable_upload); /** * Frees the given filesystem. diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index d79af533..8a684e51 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -548,7 +548,8 @@ void* guac_rdp_client_thread(void* data) { /* Allocate actual emulated filesystem */ rdp_client->filesystem = guac_rdp_fs_alloc(client, settings->drive_path, - settings->create_drive_path); + settings->create_drive_path, settings->disable_download, + settings->disable_upload); /* Expose filesystem to owner */ guac_client_for_owner(client, guac_rdp_fs_expose, @@ -617,7 +618,9 @@ void* guac_rdp_client_thread(void* data) { /* Load and expose filesystem */ rdp_client->sftp_filesystem = guac_common_ssh_create_sftp_filesystem(rdp_client->sftp_session, - settings->sftp_root_directory, NULL); + settings->sftp_root_directory, NULL, + settings->sftp_disable_download, + settings->sftp_disable_upload); /* Expose filesystem to connection owner */ guac_client_for_owner(client, diff --git a/src/protocols/rdp/user.c b/src/protocols/rdp/user.c index c2b487f6..05a7a6ac 100644 --- a/src/protocols/rdp/user.c +++ b/src/protocols/rdp/user.c @@ -131,16 +131,17 @@ int guac_rdp_user_file_handler(guac_user* user, guac_stream* stream, #ifdef ENABLE_COMMON_SSH guac_rdp_settings* settings = rdp_client->settings; - /* If SFTP is enabled, it should be used for default uploads only if RDPDR - * is not enabled or its upload directory has been set */ - if (rdp_client->sftp_filesystem != NULL) { + /* If SFTP is enabled and SFTP uploads have not been disabled, it should be + * used for default uploads only if RDPDR is not enabled or its upload + * directory has been set */ + if (rdp_client->sftp_filesystem != NULL && !settings->sftp_disable_upload) { if (!settings->drive_enabled || settings->sftp_directory != NULL) return guac_rdp_sftp_file_handler(user, stream, mimetype, filename); } #endif /* Default to using RDPDR uploads (if enabled) */ - if (rdp_client->filesystem != NULL) + if (rdp_client->filesystem != NULL && !settings->disable_upload) return guac_rdp_upload_file_handler(user, stream, mimetype, filename); /* File transfer not enabled */ diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index 32c60725..35f3b067 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -368,7 +368,7 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, /* Disable file downloads. */ settings->sftp_disable_download = guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv, - IDX_SFTP_DISABLE_DOWNLAOD, false); + IDX_SFTP_DISABLE_DOWNLOAD, false); /* Disable file uploads. */ settings->sftp_disable_upload = diff --git a/src/protocols/ssh/settings.h b/src/protocols/ssh/settings.h index 76221df6..5e79d39a 100644 --- a/src/protocols/ssh/settings.h +++ b/src/protocols/ssh/settings.h @@ -185,14 +185,14 @@ typedef struct guac_ssh_settings { * downloads will not be allowed over SFTP. If not set or set to false, file * downloads will be allowed. */ - bool disable_download; + bool sftp_disable_download; /** * Whether file uploads over SFTP should be disabled. If set to true, file * uploads will not be allowed over SFTP. If not set or set to false, file * uploads will be allowed. */ - bool disable_upload; + bool sftp_disable_upload; #ifdef ENABLE_SSH_AGENT /** diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 89572050..9ec9bbe4 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -320,7 +320,8 @@ void* ssh_client_thread(void* data) { /* Request SFTP */ ssh_client->sftp_filesystem = guac_common_ssh_create_sftp_filesystem( ssh_client->sftp_session, settings->sftp_root_directory, - NULL); + NULL, settings->sftp_disable_download, + settings->sftp_disable_upload); /* Expose filesystem to connection owner */ guac_client_for_owner(client, @@ -328,8 +329,11 @@ void* ssh_client_thread(void* data) { ssh_client->sftp_filesystem); /* Init handlers for Guacamole-specific console codes */ - ssh_client->term->upload_path_handler = guac_sftp_set_upload_path; - ssh_client->term->file_download_handler = guac_sftp_download_file; + if (!settings->sftp_disable_upload) + ssh_client->term->upload_path_handler = guac_sftp_set_upload_path; + + if (!settings->sftp_disable_download) + ssh_client->term->file_download_handler = guac_sftp_download_file; guac_client_log(client, GUAC_LOG_DEBUG, "SFTP session initialized"); diff --git a/src/protocols/ssh/user.c b/src/protocols/ssh/user.c index 8ea30a4c..853ae308 100644 --- a/src/protocols/ssh/user.c +++ b/src/protocols/ssh/user.c @@ -99,7 +99,7 @@ int guac_ssh_user_join_handler(guac_user* user, int argc, char** argv) { user->size_handler = guac_ssh_user_size_handler; /* Set generic (non-filesystem) file upload handler */ - if (settings->enable_sftp) + if (settings->enable_sftp && !settings->sftp_disable_upload) user->file_handler = guac_sftp_file_handler; } diff --git a/src/protocols/vnc/user.c b/src/protocols/vnc/user.c index 0dee5043..a3d38d79 100644 --- a/src/protocols/vnc/user.c +++ b/src/protocols/vnc/user.c @@ -101,7 +101,7 @@ int guac_vnc_user_join_handler(guac_user* user, int argc, char** argv) { #ifdef ENABLE_COMMON_SSH /* Set generic (non-filesystem) file upload handler */ - if (settings->enable_sftp) + if (settings->enable_sftp && !settings->sftp_disable_upload) user->file_handler = guac_vnc_sftp_file_handler; #endif diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index f33b267a..b88f7945 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -342,7 +342,9 @@ void* guac_vnc_client_thread(void* data) { /* Load filesystem */ vnc_client->sftp_filesystem = guac_common_ssh_create_sftp_filesystem(vnc_client->sftp_session, - settings->sftp_root_directory, NULL); + settings->sftp_root_directory, NULL, + settings->sftp_disable_download, + settings->sftp_disable_upload); /* Expose filesystem to connection owner */ guac_client_for_owner(client,