Merge pull request #54 from glyptodon/vnc-rdp-sftp
GUAC-1171: Add support for SFTP file transfer to VNC and RDP.
This commit is contained in:
commit
6f93872e0e
@ -840,6 +840,9 @@ fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_COMMON_SSH], [test "x${have_libssh2}" = "xyes" \
|
||||
-a "x${have_ssl}" = "xyes"])
|
||||
AM_COND_IF([ENABLE_COMMON_SSH],
|
||||
[AC_DEFINE([ENABLE_COMMON_SSH],,
|
||||
[Whether support for the common SSH core is enabled])])
|
||||
|
||||
AM_CONDITIONAL([ENABLE_SSH], [test "x${have_libssh2}" = "xyes" \
|
||||
-a "x${have_terminal}" = "xyes" \
|
||||
|
@ -246,8 +246,8 @@ int guac_common_ssh_sftp_handle_file_stream(guac_object* filesystem,
|
||||
guac_socket_flush(client->socket);
|
||||
}
|
||||
else {
|
||||
guac_client_log(client, GUAC_LOG_INFO, "Unable to open file \"%s\": %s",
|
||||
fullpath, libssh2_sftp_last_error(sftp_data->sftp_session));
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"Unable to open file \"%s\"", fullpath);
|
||||
guac_protocol_send_ack(client->socket, stream, "SFTP: Open failed",
|
||||
GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
|
||||
guac_socket_flush(client->socket);
|
||||
@ -350,8 +350,7 @@ guac_stream* guac_common_ssh_sftp_download_file(guac_object* filesystem,
|
||||
LIBSSH2_FXF_READ, 0);
|
||||
if (file == NULL) {
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"Unable to read file \"%s\": %s",
|
||||
filename, libssh2_sftp_last_error(sftp_data->sftp_session));
|
||||
"Unable to read file \"%s\"", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -540,8 +539,7 @@ static int guac_common_ssh_sftp_get_handler(guac_client* client,
|
||||
LIBSSH2_SFTP_HANDLE* dir = libssh2_sftp_opendir(sftp, name);
|
||||
if (dir == NULL) {
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"Unable to read directory \"%s\": %s",
|
||||
name, libssh2_sftp_last_error(sftp));
|
||||
"Unable to read directory \"%s\"", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -552,7 +550,7 @@ static int guac_common_ssh_sftp_get_handler(guac_client* client,
|
||||
list_state->directory = dir;
|
||||
list_state->sftp_data = sftp_data;
|
||||
strncpy(list_state->directory_name, name,
|
||||
sizeof(list_state->directory_name));
|
||||
sizeof(list_state->directory_name) - 1);
|
||||
|
||||
/* Allocate stream for body */
|
||||
guac_stream* stream = guac_client_alloc_stream(client);
|
||||
@ -576,8 +574,7 @@ static int guac_common_ssh_sftp_get_handler(guac_client* client,
|
||||
LIBSSH2_FXF_READ, 0);
|
||||
if (file == NULL) {
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"Unable to read file \"%s\": %s",
|
||||
name, libssh2_sftp_last_error(sftp));
|
||||
"Unable to read file \"%s\"", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -642,8 +639,8 @@ static int guac_common_ssh_sftp_put_handler(guac_client* client,
|
||||
|
||||
/* Abort on failure */
|
||||
else {
|
||||
guac_client_log(client, GUAC_LOG_INFO, "Unable to open file \"%s\": %s",
|
||||
name, libssh2_sftp_last_error(sftp));
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"Unable to open file \"%s\"", name);
|
||||
guac_protocol_send_ack(client->socket, stream, "SFTP: Open failed",
|
||||
GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
|
||||
}
|
||||
@ -665,24 +662,25 @@ guac_object* guac_common_ssh_create_sftp_filesystem(
|
||||
|
||||
guac_client* client = session->client;
|
||||
|
||||
/* Request SFTP */
|
||||
LIBSSH2_SFTP* sftp_session = libssh2_sftp_init(session->session);
|
||||
if (sftp_session == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||
"Unable to start SFTP session.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate data for SFTP session */
|
||||
guac_common_ssh_sftp_data* sftp_data =
|
||||
malloc(sizeof(guac_common_ssh_sftp_data));
|
||||
|
||||
/* Associate SSH session with SFTP data */
|
||||
sftp_data->ssh_session = session;
|
||||
sftp_data->sftp_session = sftp_session;
|
||||
|
||||
/* Initially upload files to current directory */
|
||||
strcpy(sftp_data->upload_path, ".");
|
||||
|
||||
/* Request SFTP */
|
||||
sftp_data->sftp_session = libssh2_sftp_init(session->session);
|
||||
if (sftp_data->sftp_session == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||
"Unable to start SFTP session.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Init filesystem */
|
||||
guac_object* filesystem = guac_client_alloc_object(client);
|
||||
filesystem->get_handler = guac_common_ssh_sftp_get_handler;
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef LIBSSH2_USES_GCRYPT
|
||||
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
||||
@ -373,12 +374,18 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
||||
|
||||
/* Get socket */
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Unable to create socket: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get addresses connection */
|
||||
if ((retval = getaddrinfo(hostname, port, &hints, &addresses))) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Error parsing given address or port: %s",
|
||||
gai_strerror(retval));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -422,6 +429,7 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
||||
if (current_address == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||
"Unable to connect to any addresses.");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -439,6 +447,7 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Session allocation failed.");
|
||||
free(common_session);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -178,6 +178,7 @@ int guac_common_ssh_key_sign(guac_common_ssh_key* key, const char* data,
|
||||
case SSH_KEY_RSA:
|
||||
if (RSA_sign(NID_sha1, digest, dlen, sig, &len, key->rsa) == 1)
|
||||
return len;
|
||||
break;
|
||||
|
||||
case SSH_KEY_DSA: {
|
||||
|
||||
|
@ -48,6 +48,7 @@ void guac_common_ssh_destroy_user(guac_common_ssh_user* user) {
|
||||
/* Free all other data */
|
||||
free(user->password);
|
||||
free(user->username);
|
||||
free(user);
|
||||
|
||||
}
|
||||
|
||||
|
@ -119,6 +119,7 @@ endif
|
||||
libguac_client_rdp_la_CFLAGS = \
|
||||
-Werror -Wall -Iinclude \
|
||||
@COMMON_INCLUDE@ \
|
||||
@COMMON_SSH_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
libguac_client_rdp_la_LDFLAGS = \
|
||||
@ -138,6 +139,7 @@ libguac_client_rdp_la_LIBADD = \
|
||||
guacdr_cflags = \
|
||||
-Werror -Wall -Iinclude \
|
||||
@COMMON_INCLUDE@ \
|
||||
@COMMON_SSH_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
guacdr_ldflags = \
|
||||
@ -156,6 +158,7 @@ guacdr_libadd = \
|
||||
guacsnd_cflags = \
|
||||
-Werror -Wall -Iinclude \
|
||||
@COMMON_INCLUDE@ \
|
||||
@COMMON_SSH_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
guacsnd_ldflags = \
|
||||
@ -174,6 +177,7 @@ guacsnd_libadd = \
|
||||
guacsvc_cflags = \
|
||||
-Werror -Wall -Iinclude \
|
||||
@COMMON_INCLUDE@ \
|
||||
@COMMON_SSH_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
guacsvc_ldflags = \
|
||||
@ -185,6 +189,16 @@ guacsvc_libadd = \
|
||||
@COMMON_LTLIB@ \
|
||||
@LIBGUAC_LTLIB@
|
||||
|
||||
#
|
||||
# Optional SFTP support
|
||||
#
|
||||
|
||||
if ENABLE_COMMON_SSH
|
||||
libguac_client_rdp_la_SOURCES += sftp.c
|
||||
noinst_HEADERS += sftp.h
|
||||
libguac_client_rdp_la_LIBADD += @COMMON_SSH_LTLIB@
|
||||
endif
|
||||
|
||||
#
|
||||
# Autogenerate keymaps
|
||||
#
|
||||
|
@ -35,6 +35,12 @@
|
||||
#include "rdp_svc.h"
|
||||
#include "resolution.h"
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
#include "guac_sftp.h"
|
||||
#include "guac_ssh.h"
|
||||
#include "sftp.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||
#include "rdp_disp.h"
|
||||
#endif
|
||||
@ -122,6 +128,17 @@ const char* GUAC_CLIENT_ARGS[] = {
|
||||
"enable-full-window-drag",
|
||||
"enable-desktop-composition",
|
||||
"enable-menu-animations",
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
"enable-sftp",
|
||||
"sftp-hostname",
|
||||
"sftp-port",
|
||||
"sftp-username",
|
||||
"sftp-password",
|
||||
"sftp-private-key",
|
||||
"sftp-passphrase",
|
||||
#endif
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -158,6 +175,17 @@ enum RDP_ARGS_IDX {
|
||||
IDX_ENABLE_FULL_WINDOW_DRAG,
|
||||
IDX_ENABLE_DESKTOP_COMPOSITION,
|
||||
IDX_ENABLE_MENU_ANIMATIONS,
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
IDX_ENABLE_SFTP,
|
||||
IDX_SFTP_HOSTNAME,
|
||||
IDX_SFTP_PORT,
|
||||
IDX_SFTP_USERNAME,
|
||||
IDX_SFTP_PASSWORD,
|
||||
IDX_SFTP_PRIVATE_KEY,
|
||||
IDX_SFTP_PASSPHRASE,
|
||||
#endif
|
||||
|
||||
RDP_ARGS_COUNT
|
||||
};
|
||||
|
||||
@ -276,6 +304,7 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
||||
if (guac_client_data->settings.drive_enabled) {
|
||||
guac_client_data->filesystem =
|
||||
guac_rdp_fs_alloc(client, guac_client_data->settings.drive_path);
|
||||
client->file_handler = guac_rdp_upload_file_handler;
|
||||
}
|
||||
|
||||
/* If RDPDR required, load it */
|
||||
@ -447,7 +476,6 @@ BOOL rdp_freerdp_post_connect(freerdp* instance) {
|
||||
|
||||
/* Stream handlers */
|
||||
client->clipboard_handler = guac_rdp_clipboard_handler;
|
||||
client->file_handler = guac_rdp_upload_file_handler;
|
||||
client->pipe_handler = guac_rdp_svc_pipe_handler;
|
||||
|
||||
return TRUE;
|
||||
@ -789,6 +817,90 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
||||
/* Load keymap into client */
|
||||
__guac_rdp_client_load_keymap(client, settings->server_layout);
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
guac_common_ssh_init(client);
|
||||
|
||||
/* Connect via SSH if SFTP is enabled */
|
||||
if (strcmp(argv[IDX_ENABLE_SFTP], "true") == 0) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Connecting via SSH for SFTP filesystem access.");
|
||||
|
||||
/* Parse username - use RDP username by default */
|
||||
const char* sftp_username = argv[IDX_SFTP_USERNAME];
|
||||
if (sftp_username[0] == '\0')
|
||||
sftp_username = settings->username;
|
||||
|
||||
guac_common_ssh_user* user = guac_common_ssh_create_user(sftp_username);
|
||||
|
||||
/* Import private key, if given */
|
||||
if (argv[IDX_SFTP_PRIVATE_KEY][0] != '\0') {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Authenticating with private key.");
|
||||
|
||||
/* Abort if private key cannot be read */
|
||||
if (guac_common_ssh_user_import_key(user,
|
||||
argv[IDX_SFTP_PRIVATE_KEY],
|
||||
argv[IDX_SFTP_PASSPHRASE]))
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, use specified password */
|
||||
else {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Authenticating with password.");
|
||||
|
||||
/* Parse password - use RDP password by default */
|
||||
const char* sftp_password = argv[IDX_SFTP_USERNAME];
|
||||
if (sftp_password[0] == '\0')
|
||||
sftp_password = settings->password;
|
||||
|
||||
guac_common_ssh_user_set_password(user, sftp_password);
|
||||
|
||||
}
|
||||
|
||||
/* Parse hostname - use RDP hostname by default */
|
||||
const char* sftp_hostname = argv[IDX_SFTP_HOSTNAME];
|
||||
if (sftp_hostname[0] == '\0')
|
||||
sftp_hostname = settings->hostname;
|
||||
|
||||
/* Parse port, defaulting to standard SSH port */
|
||||
const char* sftp_port = argv[IDX_SFTP_PORT];
|
||||
if (sftp_port[0] == '\0')
|
||||
sftp_port = "22";
|
||||
|
||||
/* Attempt SSH connection */
|
||||
guac_common_ssh_session* session =
|
||||
guac_common_ssh_create_session(client, sftp_hostname, sftp_port,
|
||||
user);
|
||||
|
||||
/* Fail if SSH connection does not succeed */
|
||||
if (session == NULL) {
|
||||
/* Already aborted within guac_common_ssh_create_session() */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Load and expose filesystem */
|
||||
guac_client_data->sftp_filesystem =
|
||||
guac_common_ssh_create_sftp_filesystem(session, "/");
|
||||
|
||||
/* Abort if SFTP connection fails */
|
||||
if (guac_client_data->sftp_filesystem == NULL)
|
||||
return 1;
|
||||
|
||||
/* Use SFTP for basic uploads, if drive not enabled */
|
||||
if (!settings->drive_enabled)
|
||||
client->file_handler = guac_rdp_sftp_file_handler;
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"SFTP connection succeeded.");
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Create default surface */
|
||||
guac_client_data->default_surface = guac_common_surface_alloc(client->socket, GUAC_DEFAULT_LAYER,
|
||||
settings->width, settings->height);
|
||||
|
@ -33,6 +33,10 @@
|
||||
#include "rdp_keymap.h"
|
||||
#include "rdp_settings.h"
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
#include "guac_sftp.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||
#include "rdp_disp.h"
|
||||
#endif
|
||||
@ -157,6 +161,13 @@ typedef struct rdp_guac_client_data {
|
||||
*/
|
||||
guac_rdp_fs* filesystem;
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/**
|
||||
* The exposed filesystem object, implemented with SFTP.
|
||||
*/
|
||||
guac_object* sftp_filesystem;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||
/**
|
||||
* Display size update module.
|
||||
|
@ -33,6 +33,11 @@
|
||||
#include "rdp_rail.h"
|
||||
#include "rdp_stream.h"
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
#include <guac_sftp.h>
|
||||
#include <guac_ssh.h>
|
||||
#endif
|
||||
|
||||
#include <freerdp/cache/cache.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
#include <freerdp/codec/color.h>
|
||||
@ -89,6 +94,14 @@ int rdp_guac_client_free_handler(guac_client* client) {
|
||||
if (guac_client_data->filesystem != NULL)
|
||||
guac_rdp_fs_free(guac_client_data->filesystem);
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/* Free SFTP filesystem, if loaded */
|
||||
if (guac_client_data->sftp_filesystem)
|
||||
guac_common_ssh_destroy_sftp_filesystem(guac_client_data->sftp_filesystem);
|
||||
|
||||
guac_common_ssh_uninit();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||
/* Free display update module */
|
||||
guac_rdp_disp_free(guac_client_data->disp);
|
||||
|
@ -486,7 +486,7 @@ int guac_rdp_download_get_handler(guac_client* client, guac_object* object,
|
||||
rdp_stream->ls_status.fs = fs;
|
||||
rdp_stream->ls_status.file_id = file_id;
|
||||
strncpy(rdp_stream->ls_status.directory_name, name,
|
||||
sizeof(rdp_stream->ls_status.directory_name));
|
||||
sizeof(rdp_stream->ls_status.directory_name) - 1);
|
||||
|
||||
/* Allocate stream for body */
|
||||
guac_stream* stream = guac_client_alloc_stream(client);
|
||||
|
43
src/protocols/rdp/sftp.c
Normal file
43
src/protocols/rdp/sftp.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "guac_sftp.h"
|
||||
#include "sftp.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/stream.h>
|
||||
|
||||
int guac_rdp_sftp_file_handler(guac_client* client, guac_stream* stream,
|
||||
char* mimetype, char* filename) {
|
||||
|
||||
rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data;
|
||||
guac_object* filesystem = client_data->sftp_filesystem;
|
||||
|
||||
/* Handle file upload */
|
||||
return guac_common_ssh_sftp_handle_file_stream(filesystem, stream,
|
||||
mimetype, filename);
|
||||
|
||||
}
|
||||
|
55
src/protocols/rdp/sftp.h
Normal file
55
src/protocols/rdp/sftp.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_RDP_SFTP_H
|
||||
#define GUAC_RDP_SFTP_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/stream.h>
|
||||
|
||||
/**
|
||||
* Handles an incoming stream from a Guacamole "file" instruction, saving the
|
||||
* contents of that stream to the file having the given name.
|
||||
*
|
||||
* @param client
|
||||
* The client receiving the uploaded file.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the uploaded file data will be received.
|
||||
*
|
||||
* @param mimetype
|
||||
* The mimetype of the data being received.
|
||||
*
|
||||
* @param filename
|
||||
* The filename of the file to write to.
|
||||
*
|
||||
* @return
|
||||
* Zero if the incoming stream has been handled successfully, non-zero on
|
||||
* failure.
|
||||
*/
|
||||
int guac_rdp_sftp_file_handler(guac_client* client, guac_stream* stream,
|
||||
char* mimetype, char* filename);
|
||||
|
||||
#endif
|
||||
|
@ -46,6 +46,7 @@ endif
|
||||
libguac_client_vnc_la_CFLAGS = \
|
||||
-Werror -Wall -pedantic -Iinclude \
|
||||
@COMMON_INCLUDE@ \
|
||||
@COMMON_SSH_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
libguac_client_vnc_la_LDFLAGS = \
|
||||
@ -58,3 +59,10 @@ libguac_client_vnc_la_LIBADD = \
|
||||
@COMMON_LTLIB@ \
|
||||
@LIBGUAC_LTLIB@
|
||||
|
||||
# Optional SFTP support
|
||||
if ENABLE_COMMON_SSH
|
||||
libguac_client_vnc_la_SOURCES += sftp.c
|
||||
noinst_HEADERS += sftp.h
|
||||
libguac_client_vnc_la_LIBADD += @COMMON_SSH_LTLIB@
|
||||
endif
|
||||
|
||||
|
@ -34,6 +34,12 @@
|
||||
#include "pulse.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
#include "guac_sftp.h"
|
||||
#include "guac_ssh.h"
|
||||
#include "sftp.h"
|
||||
#endif
|
||||
|
||||
#include <rfb/rfbclient.h>
|
||||
#include <rfb/rfbproto.h>
|
||||
#include <guacamole/client.h>
|
||||
@ -71,6 +77,16 @@ const char* GUAC_CLIENT_ARGS[] = {
|
||||
"listen-timeout",
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
"enable-sftp",
|
||||
"sftp-hostname",
|
||||
"sftp-port",
|
||||
"sftp-username",
|
||||
"sftp-password",
|
||||
"sftp-private-key",
|
||||
"sftp-passphrase",
|
||||
#endif
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -101,6 +117,16 @@ enum VNC_ARGS_IDX {
|
||||
IDX_LISTEN_TIMEOUT,
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
IDX_ENABLE_SFTP,
|
||||
IDX_SFTP_HOSTNAME,
|
||||
IDX_SFTP_PORT,
|
||||
IDX_SFTP_USERNAME,
|
||||
IDX_SFTP_PASSWORD,
|
||||
IDX_SFTP_PRIVATE_KEY,
|
||||
IDX_SFTP_PASSPHRASE,
|
||||
#endif
|
||||
|
||||
VNC_ARGS_COUNT
|
||||
};
|
||||
|
||||
@ -337,6 +363,77 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
||||
} /* end if audio enabled */
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
guac_common_ssh_init(client);
|
||||
|
||||
/* Connect via SSH if SFTP is enabled */
|
||||
if (strcmp(argv[IDX_ENABLE_SFTP], "true") == 0) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Connecting via SSH for SFTP filesystem access.");
|
||||
|
||||
guac_common_ssh_user* user =
|
||||
guac_common_ssh_create_user(argv[IDX_SFTP_USERNAME]);
|
||||
|
||||
/* Import private key, if given */
|
||||
if (argv[IDX_SFTP_PRIVATE_KEY][0] != '\0') {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Authenticating with private key.");
|
||||
|
||||
/* Abort if private key cannot be read */
|
||||
if (guac_common_ssh_user_import_key(user,
|
||||
argv[IDX_SFTP_PRIVATE_KEY],
|
||||
argv[IDX_SFTP_PASSPHRASE]))
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, use specified password */
|
||||
else {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Authenticating with password.");
|
||||
guac_common_ssh_user_set_password(user, argv[IDX_SFTP_PASSWORD]);
|
||||
}
|
||||
|
||||
/* Parse hostname - use VNC hostname by default */
|
||||
const char* sftp_hostname = argv[IDX_SFTP_HOSTNAME];
|
||||
if (sftp_hostname[0] == '\0')
|
||||
sftp_hostname = guac_client_data->hostname;
|
||||
|
||||
/* Parse port, defaulting to standard SSH port */
|
||||
const char* sftp_port = argv[IDX_SFTP_PORT];
|
||||
if (sftp_port[0] == '\0')
|
||||
sftp_port = "22";
|
||||
|
||||
/* Attempt SSH connection */
|
||||
guac_common_ssh_session* session =
|
||||
guac_common_ssh_create_session(client, sftp_hostname, sftp_port,
|
||||
user);
|
||||
|
||||
/* Fail if SSH connection does not succeed */
|
||||
if (session == NULL) {
|
||||
/* Already aborted within guac_common_ssh_create_session() */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Load and expose filesystem */
|
||||
guac_client_data->sftp_filesystem =
|
||||
guac_common_ssh_create_sftp_filesystem(session, "/");
|
||||
|
||||
/* Abort if SFTP connection fails */
|
||||
if (guac_client_data->sftp_filesystem == NULL)
|
||||
return 1;
|
||||
|
||||
/* Set file handler for basic uploads */
|
||||
client->file_handler = guac_vnc_sftp_file_handler;
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"SFTP connection succeeded.");
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set remaining client data */
|
||||
guac_client_data->rfb_client = rfb_client;
|
||||
guac_client_data->copy_rect_used = 0;
|
||||
|
@ -36,6 +36,10 @@
|
||||
#include <pulse/pulseaudio.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
#include "guac_sftp.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The maximum duration of a frame in milliseconds.
|
||||
*/
|
||||
@ -186,6 +190,13 @@ typedef struct vnc_guac_client_data {
|
||||
*/
|
||||
guac_common_surface* default_surface;
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/**
|
||||
* The exposed filesystem object, implemented with SFTP.
|
||||
*/
|
||||
guac_object* sftp_filesystem;
|
||||
#endif
|
||||
|
||||
} vnc_guac_client_data;
|
||||
|
||||
#endif
|
||||
|
@ -31,6 +31,11 @@
|
||||
#include <guacamole/timestamp.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
#include <guac_sftp.h>
|
||||
#include <guac_ssh.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PULSE
|
||||
#include "pulse.h"
|
||||
#endif
|
||||
@ -135,6 +140,14 @@ int vnc_guac_client_free_handler(guac_client* client) {
|
||||
guac_pa_stop_stream(client);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/* Free SFTP filesystem, if loaded */
|
||||
if (guac_client_data->sftp_filesystem)
|
||||
guac_common_ssh_destroy_sftp_filesystem(guac_client_data->sftp_filesystem);
|
||||
|
||||
guac_common_ssh_uninit();
|
||||
#endif
|
||||
|
||||
/* Free encodings string, if used */
|
||||
if (guac_client_data->encodings != NULL)
|
||||
free(guac_client_data->encodings);
|
||||
|
43
src/protocols/vnc/sftp.c
Normal file
43
src/protocols/vnc/sftp.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "guac_sftp.h"
|
||||
#include "sftp.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/stream.h>
|
||||
|
||||
int guac_vnc_sftp_file_handler(guac_client* client, guac_stream* stream,
|
||||
char* mimetype, char* filename) {
|
||||
|
||||
vnc_guac_client_data* client_data = (vnc_guac_client_data*) client->data;
|
||||
guac_object* filesystem = client_data->sftp_filesystem;
|
||||
|
||||
/* Handle file upload */
|
||||
return guac_common_ssh_sftp_handle_file_stream(filesystem, stream,
|
||||
mimetype, filename);
|
||||
|
||||
}
|
||||
|
55
src/protocols/vnc/sftp.h
Normal file
55
src/protocols/vnc/sftp.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_VNC_SFTP_H
|
||||
#define GUAC_VNC_SFTP_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/stream.h>
|
||||
|
||||
/**
|
||||
* Handles an incoming stream from a Guacamole "file" instruction, saving the
|
||||
* contents of that stream to the file having the given name.
|
||||
*
|
||||
* @param client
|
||||
* The client receiving the uploaded file.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the uploaded file data will be received.
|
||||
*
|
||||
* @param mimetype
|
||||
* The mimetype of the data being received.
|
||||
*
|
||||
* @param filename
|
||||
* The filename of the file to write to.
|
||||
*
|
||||
* @return
|
||||
* Zero if the incoming stream has been handled successfully, non-zero on
|
||||
* failure.
|
||||
*/
|
||||
int guac_vnc_sftp_file_handler(guac_client* client, guac_stream* stream,
|
||||
char* mimetype, char* filename);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user