GUACAMOLE-249: Migrate SVC support to FreeRDP 2.0.0 plugin API.
This commit is contained in:
parent
fa0ad267b8
commit
233c0555c3
@ -60,6 +60,7 @@ libguac_client_rdp_la_SOURCES = \
|
|||||||
rdp_settings.c \
|
rdp_settings.c \
|
||||||
rdp_stream.c \
|
rdp_stream.c \
|
||||||
resolution.c \
|
resolution.c \
|
||||||
|
svc.c \
|
||||||
unicode.c \
|
unicode.c \
|
||||||
user.c
|
user.c
|
||||||
|
|
||||||
@ -76,7 +77,6 @@ noinst_HEADERS = \
|
|||||||
guac_rdpdr/rdpdr_service.h \
|
guac_rdpdr/rdpdr_service.h \
|
||||||
guac_rdpsnd/rdpsnd_messages.h \
|
guac_rdpsnd/rdpsnd_messages.h \
|
||||||
guac_rdpsnd/rdpsnd_service.h \
|
guac_rdpsnd/rdpsnd_service.h \
|
||||||
guac_svc/svc_service.h \
|
|
||||||
audio_input.h \
|
audio_input.h \
|
||||||
client.h \
|
client.h \
|
||||||
clipboard.h \
|
clipboard.h \
|
||||||
@ -101,6 +101,7 @@ noinst_HEADERS = \
|
|||||||
rdp_status.h \
|
rdp_status.h \
|
||||||
rdp_stream.h \
|
rdp_stream.h \
|
||||||
resolution.h \
|
resolution.h \
|
||||||
|
svc.h \
|
||||||
unicode.h \
|
unicode.h \
|
||||||
user.h
|
user.h
|
||||||
|
|
||||||
@ -125,11 +126,11 @@ libguac_client_rdp_la_LIBADD = \
|
|||||||
# Plugins for FreeRDP
|
# Plugins for FreeRDP
|
||||||
#
|
#
|
||||||
|
|
||||||
freerdp_LTLIBRARIES = \
|
freerdp_LTLIBRARIES = \
|
||||||
libguacai-client.la
|
libguacai-client.la \
|
||||||
# libguacdr-client.la \
|
libguacsvc-client.la
|
||||||
# libguacsnd-client.la \
|
# libguacdr-client.la
|
||||||
# libguacsvc-client.la
|
# libguacsnd-client.la
|
||||||
|
|
||||||
freerdpdir = ${libdir}/freerdp2
|
freerdpdir = ${libdir}/freerdp2
|
||||||
|
|
||||||
@ -221,25 +222,25 @@ libguacai_client_la_LIBADD = \
|
|||||||
# Static Virtual Channels
|
# Static Virtual Channels
|
||||||
#
|
#
|
||||||
|
|
||||||
#libguacsvc_client_la_SOURCES = \
|
libguacsvc_client_la_SOURCES = \
|
||||||
# guac_svc/svc_service.c \
|
guac_svc/svc_service.c \
|
||||||
# rdp_svc.c
|
svc.c
|
||||||
#
|
|
||||||
#libguacsvc_client_la_CFLAGS = \
|
libguacsvc_client_la_CFLAGS = \
|
||||||
# -Werror -Wall -Iinclude \
|
-Werror -Wall -Iinclude \
|
||||||
# @COMMON_INCLUDE@ \
|
@COMMON_INCLUDE@ \
|
||||||
# @COMMON_SSH_INCLUDE@ \
|
@COMMON_SSH_INCLUDE@ \
|
||||||
# @LIBGUAC_INCLUDE@ \
|
@LIBGUAC_INCLUDE@ \
|
||||||
# @RDP_CFLAGS@
|
@RDP_CFLAGS@
|
||||||
#
|
|
||||||
#libguacsvc_client_la_LDFLAGS = \
|
libguacsvc_client_la_LDFLAGS = \
|
||||||
# -module -avoid-version -shared \
|
-module -avoid-version -shared \
|
||||||
# @PTHREAD_LIBS@ \
|
@PTHREAD_LIBS@ \
|
||||||
# @RDP_LIBS@
|
@RDP_LIBS@
|
||||||
#
|
|
||||||
#libguacsvc_client_la_LIBADD = \
|
libguacsvc_client_la_LIBADD = \
|
||||||
# @COMMON_LTLIB@ \
|
@COMMON_LTLIB@ \
|
||||||
# @LIBGUAC_LTLIB@
|
@LIBGUAC_LTLIB@
|
||||||
|
|
||||||
#
|
#
|
||||||
# Optional SFTP support
|
# Optional SFTP support
|
||||||
|
@ -19,13 +19,12 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "svc_service.h"
|
#include "svc.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <freerdp/constants.h>
|
#include <freerdp/constants.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/protocol.h>
|
#include <guacamole/protocol.h>
|
||||||
#include <guacamole/socket.h>
|
#include <guacamole/socket.h>
|
||||||
@ -33,60 +32,142 @@
|
|||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point for arbitrary SVC.
|
* Processes data received along an SVC via a CHANNEL_EVENT_DATA_RECEIVED
|
||||||
|
* event, forwarding the data along an established, outbound pipe stream to the
|
||||||
|
* Guacamole client.
|
||||||
|
*
|
||||||
|
* @param svc
|
||||||
|
* The guac_rdp_svc structure representing the SVC that received the data.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* The data that was received.
|
||||||
|
*
|
||||||
|
* @param length
|
||||||
|
* The number of bytes received.
|
||||||
*/
|
*/
|
||||||
int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) {
|
static void guac_rdp_svc_process_receive(guac_rdp_svc* svc,
|
||||||
|
void* data, int length) {
|
||||||
|
|
||||||
/* Gain access to plugin data */
|
/* Fail if output not created */
|
||||||
CHANNEL_ENTRY_POINTS_FREERDP* entry_points_ex =
|
if (svc->output_pipe == NULL) {
|
||||||
(CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints;
|
guac_client_log(svc->client, GUAC_LOG_WARNING, "%i bytes of data "
|
||||||
|
"received from within the remote desktop session for SVC "
|
||||||
|
"\"%s\" are being dropped because the outbound pipe stream "
|
||||||
|
"for that SVC is not yet open. This should NOT happen.",
|
||||||
|
length, svc->channel_def.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate plugin */
|
/* Send blob */
|
||||||
guac_svcPlugin* svc_plugin =
|
guac_protocol_send_blob(svc->client->socket, svc->output_pipe, data, length);
|
||||||
(guac_svcPlugin*) calloc(1, sizeof(guac_svcPlugin));
|
guac_socket_flush(svc->client->socket);
|
||||||
|
|
||||||
/* Get SVC descriptor from plugin parameters */
|
|
||||||
guac_rdp_svc* svc = (guac_rdp_svc*) entry_points_ex->pExtendedData;
|
|
||||||
|
|
||||||
/* Init channel def */
|
|
||||||
guac_strlcpy(svc_plugin->plugin.channel_def.name, svc->name,
|
|
||||||
GUAC_RDP_SVC_MAX_LENGTH);
|
|
||||||
svc_plugin->plugin.channel_def.options =
|
|
||||||
CHANNEL_OPTION_INITIALIZED
|
|
||||||
| CHANNEL_OPTION_ENCRYPT_RDP
|
|
||||||
| CHANNEL_OPTION_COMPRESS_RDP;
|
|
||||||
|
|
||||||
/* Init plugin */
|
|
||||||
svc_plugin->svc = svc;
|
|
||||||
|
|
||||||
/* Set callbacks */
|
|
||||||
svc_plugin->plugin.connect_callback = guac_svc_process_connect;
|
|
||||||
svc_plugin->plugin.receive_callback = guac_svc_process_receive;
|
|
||||||
svc_plugin->plugin.event_callback = guac_svc_process_event;
|
|
||||||
svc_plugin->plugin.terminate_callback = guac_svc_process_terminate;
|
|
||||||
|
|
||||||
/* Store plugin reference in SVC */
|
|
||||||
svc->plugin = (rdpSvcPlugin*) svc_plugin;
|
|
||||||
|
|
||||||
/* Finish init */
|
|
||||||
svc_plugin_init((rdpSvcPlugin*) svc_plugin, pEntryPoints);
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Service Handlers
|
* Event handler for events which deal with data transmitted over an open SVC.
|
||||||
|
* This specific implementation of the event handler currently handles only the
|
||||||
|
* CHANNEL_EVENT_DATA_RECEIVED event, delegating actual handling of that event
|
||||||
|
* to guac_rdp_svc_process_receive().
|
||||||
|
*
|
||||||
|
* The FreeRDP requirements for this function follow those of the
|
||||||
|
* VirtualChannelOpenEventEx callback defined within Microsoft's RDP API:
|
||||||
|
*
|
||||||
|
* https://docs.microsoft.com/en-us/previous-versions/windows/embedded/aa514754%28v%3dmsdn.10%29
|
||||||
|
*
|
||||||
|
* @param user_param
|
||||||
|
* The pointer to arbitrary data originally passed via the first parameter
|
||||||
|
* of the pVirtualChannelInitEx() function call when the associated channel
|
||||||
|
* was initialized. The pVirtualChannelInitEx() function is exposed within
|
||||||
|
* the channel entry points structure.
|
||||||
|
*
|
||||||
|
* @param open_handle
|
||||||
|
* The handle which identifies the channel itself, typically referred to
|
||||||
|
* within the FreeRDP source as OpenHandle.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* An integer representing the event that should be handled. This will be
|
||||||
|
* either CHANNEL_EVENT_DATA_RECEIVED, CHANNEL_EVENT_WRITE_CANCELLED, or
|
||||||
|
* CHANNEL_EVENT_WRITE_COMPLETE.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* The data received, for CHANNEL_EVENT_DATA_RECEIVED events, and the value
|
||||||
|
* passed as user data to pVirtualChannelWriteEx() for
|
||||||
|
* CHANNEL_EVENT_WRITE_* events (note that user data for
|
||||||
|
* pVirtualChannelWriteEx() as implemented by FreeRDP MUST either be NULL
|
||||||
|
* or a wStream containing the data written).
|
||||||
|
*
|
||||||
|
* @param data_length
|
||||||
|
* The number of bytes of event-specific data.
|
||||||
|
*
|
||||||
|
* @param total_length
|
||||||
|
* The total number of bytes written to the RDP server in a single write
|
||||||
|
* operation.
|
||||||
|
*
|
||||||
|
* NOTE: The meaning of total_length is unclear. The above description was
|
||||||
|
* written mainly through referencing the documentation in MSDN. Real-world
|
||||||
|
* use will need to be consulted, likely within the FreeRDP source, before
|
||||||
|
* this value can be reliably used. The current implementation of this
|
||||||
|
* handler ignores this parameter.
|
||||||
|
*
|
||||||
|
* @param data_flags
|
||||||
|
* The result of a bitwise OR of the CHANNEL_FLAG_* flags which apply to
|
||||||
|
* the data received. This value is relevant only to
|
||||||
|
* CHANNEL_EVENT_DATA_RECEIVED events. Valid flags are CHANNEL_FLAG_FIRST,
|
||||||
|
* CHANNEL_FLAG_LAST, and CHANNEL_FLAG_ONLY. The flag CHANNEL_FLAG_MIDDLE
|
||||||
|
* is not itself a flag, but the absence of both CHANNEL_FLAG_FIRST and
|
||||||
|
* CHANNEL_FLAG_LAST.
|
||||||
*/
|
*/
|
||||||
|
static VOID guac_rdp_svc_handle_open_event(LPVOID user_param,
|
||||||
|
DWORD open_handle, UINT event, LPVOID data, UINT32 data_length,
|
||||||
|
UINT32 total_length, UINT32 data_flags) {
|
||||||
|
|
||||||
void guac_svc_process_connect(rdpSvcPlugin* plugin) {
|
/* Ignore all events except for received data */
|
||||||
|
if (event != CHANNEL_EVENT_DATA_RECEIVED)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Get corresponding guac_rdp_svc */
|
guac_rdp_svc* svc = (guac_rdp_svc*) user_param;
|
||||||
guac_svcPlugin* svc_plugin = (guac_svcPlugin*) plugin;
|
|
||||||
guac_rdp_svc* svc = svc_plugin->svc;
|
|
||||||
|
|
||||||
/* NULL out pExtendedData so we don't lose our guac_rdp_svc due to an
|
/* Validate relevant handle matches that of SVC */
|
||||||
* automatic free() within libfreerdp */
|
if (open_handle != svc->open_handle) {
|
||||||
plugin->channel_entry_points.pExtendedData = NULL;
|
guac_client_log(svc->client, GUAC_LOG_WARNING, "%i bytes of data "
|
||||||
|
"received from within the remote desktop session for SVC "
|
||||||
|
"\"%s\" are being dropped because the relevant open handle "
|
||||||
|
"(0x%X) does not match the open handle of the SVC (0x%X).",
|
||||||
|
data_length, svc->channel_def.name, open_handle,
|
||||||
|
svc->open_handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
guac_rdp_svc_process_receive(svc, data, data_length);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a CHANNEL_EVENT_CONNECTED event, completing the
|
||||||
|
* connection/initialization process of the SVC.
|
||||||
|
*
|
||||||
|
* @param svc
|
||||||
|
* The guac_rdp_svc structure representing the SVC that is now connected.
|
||||||
|
*/
|
||||||
|
static void guac_rdp_svc_process_connect(guac_rdp_svc* svc) {
|
||||||
|
|
||||||
|
/* Open FreeRDP side of connected channel */
|
||||||
|
UINT32 open_status =
|
||||||
|
svc->entry_points.pVirtualChannelOpenEx(svc->init_handle,
|
||||||
|
&svc->open_handle, svc->channel_def.name,
|
||||||
|
guac_rdp_svc_handle_open_event);
|
||||||
|
|
||||||
|
/* Warn if the channel cannot be opened after all */
|
||||||
|
if (open_status != CHANNEL_RC_OK) {
|
||||||
|
guac_client_log(svc->client, GUAC_LOG_WARNING, "SVC \"%s\" could not "
|
||||||
|
"be opened: %s (error %i)", svc->channel_def.name,
|
||||||
|
WTSErrorToString(open_status), open_status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SVC may now receive data from client */
|
||||||
|
guac_rdp_svc_add(svc->client, svc);
|
||||||
|
|
||||||
/* Create pipe */
|
/* Create pipe */
|
||||||
svc->output_pipe = guac_client_alloc_stream(svc->client);
|
svc->output_pipe = guac_client_alloc_stream(svc->client);
|
||||||
@ -96,50 +177,135 @@ void guac_svc_process_connect(rdpSvcPlugin* plugin) {
|
|||||||
|
|
||||||
/* Log connection to static channel */
|
/* Log connection to static channel */
|
||||||
guac_client_log(svc->client, GUAC_LOG_INFO,
|
guac_client_log(svc->client, GUAC_LOG_INFO,
|
||||||
"Static channel \"%s\" connected.", svc->name);
|
"Static channel \"%s\" connected.", svc->channel_def.name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_svc_process_terminate(rdpSvcPlugin* plugin) {
|
/**
|
||||||
|
* Processes a CHANNEL_EVENT_TERMINATED event, freeing all resources associated
|
||||||
/* Get corresponding guac_rdp_svc */
|
* with the SVC.
|
||||||
guac_svcPlugin* svc_plugin = (guac_svcPlugin*) plugin;
|
*
|
||||||
guac_rdp_svc* svc = svc_plugin->svc;
|
* @param svc
|
||||||
|
* The guac_rdp_svc structure representing the SVC that has been
|
||||||
|
* terminated.
|
||||||
|
*/
|
||||||
|
static void guac_rdp_svc_process_terminate(guac_rdp_svc* svc) {
|
||||||
|
|
||||||
/* Remove and free SVC */
|
/* Remove and free SVC */
|
||||||
guac_client_log(svc->client, GUAC_LOG_INFO, "Closing channel \"%s\"...", svc->name);
|
guac_client_log(svc->client, GUAC_LOG_INFO, "Closing channel \"%s\"...", svc->channel_def.name);
|
||||||
guac_rdp_remove_svc(svc->client, svc->name);
|
guac_rdp_svc_remove(svc->client, svc->channel_def.name);
|
||||||
free(svc);
|
free(svc);
|
||||||
|
|
||||||
free(plugin);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_svc_process_event(rdpSvcPlugin* plugin, wMessage* event) {
|
/**
|
||||||
freerdp_event_free(event);
|
* Event handler for events which deal with the overall lifecycle of an SVC.
|
||||||
}
|
* This specific implementation of the event handler currently handles only
|
||||||
|
* CHANNEL_EVENT_CONNECTED and CHANNEL_EVENT_TERMINATED events, delegating
|
||||||
|
* actual handling of those events to guac_rdp_svc_process_connect() and
|
||||||
|
* guac_rdp_svc_process_terminate() respectively.
|
||||||
|
*
|
||||||
|
* The FreeRDP requirements for this function follow those of the
|
||||||
|
* VirtualChannelInitEventEx callback defined within Microsoft's RDP API:
|
||||||
|
*
|
||||||
|
* https://docs.microsoft.com/en-us/previous-versions/windows/embedded/aa514727%28v%3dmsdn.10%29
|
||||||
|
*
|
||||||
|
* @param user_param
|
||||||
|
* The pointer to arbitrary data originally passed via the first parameter
|
||||||
|
* of the pVirtualChannelInitEx() function call when the associated channel
|
||||||
|
* was initialized. The pVirtualChannelInitEx() function is exposed within
|
||||||
|
* the channel entry points structure.
|
||||||
|
*
|
||||||
|
* @param init_handle
|
||||||
|
* The handle which identifies the client connection, typically referred to
|
||||||
|
* within the FreeRDP source as pInitHandle.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* An integer representing the event that should be handled. This will be
|
||||||
|
* either CHANNEL_EVENT_CONNECTED, CHANNEL_EVENT_DISCONNECTED,
|
||||||
|
* CHANNEL_EVENT_INITIALIZED, CHANNEL_EVENT_TERMINATED, or
|
||||||
|
* CHANNEL_EVENT_V1_CONNECTED.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* NULL in all cases except the CHANNEL_EVENT_CONNECTED event, in which
|
||||||
|
* case this is a null-terminated string containing the name of the server.
|
||||||
|
*
|
||||||
|
* @param data_length
|
||||||
|
* The number of bytes of data, if any.
|
||||||
|
*/
|
||||||
|
static VOID guac_rdp_svc_handle_init_event(LPVOID user_param,
|
||||||
|
LPVOID init_handle, UINT event, LPVOID data, UINT data_length) {
|
||||||
|
|
||||||
void guac_svc_process_receive(rdpSvcPlugin* plugin,
|
guac_rdp_svc* svc = (guac_rdp_svc*) user_param;
|
||||||
wStream* input_stream) {
|
|
||||||
|
|
||||||
/* Get corresponding guac_rdp_svc */
|
/* Validate relevant handle matches that of SVC */
|
||||||
guac_svcPlugin* svc_plugin = (guac_svcPlugin*) plugin;
|
if (init_handle != svc->init_handle) {
|
||||||
guac_rdp_svc* svc = svc_plugin->svc;
|
guac_client_log(svc->client, GUAC_LOG_WARNING, "An init event (#%i) "
|
||||||
|
"for SVC \"%s\" has been dropped because the relevant init "
|
||||||
/* Fail if output not created */
|
"handle (0x%X) does not match the init handle of the SVC "
|
||||||
if (svc->output_pipe == NULL) {
|
"(0x%X).", event, svc->channel_def.name, init_handle,
|
||||||
guac_client_log(svc->client, GUAC_LOG_ERROR,
|
svc->init_handle);
|
||||||
"Output for channel \"%s\" dropped.",
|
|
||||||
svc->name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send blob */
|
switch (event) {
|
||||||
guac_protocol_send_blob(svc->client->socket, svc->output_pipe,
|
|
||||||
Stream_Buffer(input_stream),
|
|
||||||
Stream_Length(input_stream));
|
|
||||||
|
|
||||||
guac_socket_flush(svc->client->socket);
|
/* The remote desktop side of the SVC has been connected */
|
||||||
|
case CHANNEL_EVENT_CONNECTED:
|
||||||
|
guac_rdp_svc_process_connect(svc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* The channel has disconnected and now must be cleaned up */
|
||||||
|
case CHANNEL_EVENT_TERMINATED:
|
||||||
|
guac_rdp_svc_process_terminate(svc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point for FreeRDP plugins. This function is automatically invoked when
|
||||||
|
* the plugin is loaded.
|
||||||
|
*
|
||||||
|
* @param entry_points
|
||||||
|
* Functions and data specific to the FreeRDP side of the virtual channel
|
||||||
|
* and plugin. This structure must be copied within implementation-specific
|
||||||
|
* storage such that the functions it references can be invoked when
|
||||||
|
* needed.
|
||||||
|
*
|
||||||
|
* @param init_handle
|
||||||
|
* The handle which identifies the client connection, typically referred to
|
||||||
|
* within the FreeRDP source as pInitHandle. This handle is also provided
|
||||||
|
* to the channel init event handler. The handle must eventually be used
|
||||||
|
* within the channel open event handler to obtain a handle to the channel
|
||||||
|
* itself.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* TRUE if the plugin has initialized successfully, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
BOOL VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS entry_points,
|
||||||
|
PVOID init_handle) {
|
||||||
|
|
||||||
|
CHANNEL_ENTRY_POINTS_FREERDP_EX* entry_points_ex =
|
||||||
|
(CHANNEL_ENTRY_POINTS_FREERDP_EX*) entry_points;
|
||||||
|
|
||||||
|
/* Get structure representing the Guacamole side of the SVC from plugin
|
||||||
|
* parameters */
|
||||||
|
guac_rdp_svc* svc = (guac_rdp_svc*) entry_points_ex->pExtendedData;
|
||||||
|
|
||||||
|
/* Copy FreeRDP data into SVC structure for future reference */
|
||||||
|
svc->entry_points = *entry_points_ex;
|
||||||
|
svc->init_handle = init_handle;
|
||||||
|
|
||||||
|
/* Complete initialization */
|
||||||
|
if (svc->entry_points.pVirtualChannelInitEx(svc, svc, init_handle,
|
||||||
|
&svc->channel_def, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
|
||||||
|
guac_rdp_svc_handle_init_event) != CHANNEL_RC_OK) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __GUAC_SVC_SERVICE_H
|
|
||||||
#define __GUAC_SVC_SERVICE_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "rdp_svc.h"
|
|
||||||
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <winpr/stream.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure representing the current state of an arbitrary static virtual
|
|
||||||
* channel.
|
|
||||||
*/
|
|
||||||
typedef struct guac_svcPlugin {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The FreeRDP parts of this plugin. This absolutely MUST be first.
|
|
||||||
* FreeRDP depends on accessing this structure as if it were an instance
|
|
||||||
* of rdpSvcPlugin.
|
|
||||||
*/
|
|
||||||
rdpSvcPlugin plugin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Guacamole-specific SVC structure describing the channel this
|
|
||||||
* instance represents.
|
|
||||||
*/
|
|
||||||
guac_rdp_svc* svc;
|
|
||||||
|
|
||||||
} guac_svcPlugin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler called when this plugin is loaded by FreeRDP.
|
|
||||||
*/
|
|
||||||
void guac_svc_process_connect(rdpSvcPlugin* plugin);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler called when this plugin receives data along its designated channel.
|
|
||||||
*/
|
|
||||||
void guac_svc_process_receive(rdpSvcPlugin* plugin,
|
|
||||||
wStream* input_stream);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler called when this plugin is being unloaded.
|
|
||||||
*/
|
|
||||||
void guac_svc_process_terminate(rdpSvcPlugin* plugin);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler called when this plugin receives an event.
|
|
||||||
*/
|
|
||||||
void guac_svc_process_event(rdpSvcPlugin* plugin, wMessage* event);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -38,9 +38,7 @@
|
|||||||
#include "rdp_glyph.h"
|
#include "rdp_glyph.h"
|
||||||
#include "rdp_pointer.h"
|
#include "rdp_pointer.h"
|
||||||
#include "rdp_stream.h"
|
#include "rdp_stream.h"
|
||||||
#if 0
|
#include "svc.h"
|
||||||
#include "rdp_svc.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_COMMON_SSH
|
#ifdef ENABLE_COMMON_SSH
|
||||||
#include "common-ssh/sftp.h"
|
#include "common-ssh/sftp.h"
|
||||||
@ -131,35 +129,15 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
if (settings->remote_app != NULL)
|
if (settings->remote_app != NULL)
|
||||||
guac_rdp_rail_load_plugin(context);
|
guac_rdp_rail_load_plugin(context);
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Load SVC plugin instances for all static channels */
|
/* Load SVC plugin instances for all static channels */
|
||||||
if (settings->svc_names != NULL) {
|
if (settings->svc_names != NULL) {
|
||||||
|
|
||||||
char** current = settings->svc_names;
|
char** current = settings->svc_names;
|
||||||
do {
|
do {
|
||||||
|
guac_rdp_svc_load_plugin(context, *current);
|
||||||
guac_rdp_svc* svc = guac_rdp_alloc_svc(client, *current);
|
|
||||||
|
|
||||||
/* Attempt to load guacsvc plugin for new static channel */
|
|
||||||
if (guac_freerdp_channels_load_plugin(channels, instance->settings,
|
|
||||||
"guacsvc", svc)) {
|
|
||||||
guac_client_log(client, GUAC_LOG_WARNING,
|
|
||||||
"Cannot create static channel \"%s\": failed to load guacsvc plugin.",
|
|
||||||
svc->name);
|
|
||||||
guac_rdp_free_svc(svc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store and log on success */
|
|
||||||
else {
|
|
||||||
guac_rdp_add_svc(client, svc);
|
|
||||||
guac_client_log(client, GUAC_LOG_INFO, "Created static channel \"%s\"...",
|
|
||||||
svc->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (*(++current) != NULL);
|
} while (*(++current) != NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Load plugin providing Dynamic Virtual Channel support, if required */
|
/* Load plugin providing Dynamic Virtual Channel support, if required */
|
||||||
if (instance->settings->SupportDynamicChannels &&
|
if (instance->settings->SupportDynamicChannels &&
|
||||||
|
@ -22,9 +22,6 @@
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
#include "rdp_fs.h"
|
#include "rdp_fs.h"
|
||||||
#if 0
|
|
||||||
#include "rdp_svc.h"
|
|
||||||
#endif
|
|
||||||
#include "rdp_stream.h"
|
#include "rdp_stream.h"
|
||||||
|
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
@ -119,39 +116,6 @@ int guac_rdp_upload_file_handler(guac_user* user, guac_stream* stream,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int guac_rdp_svc_pipe_handler(guac_user* user, guac_stream* stream,
|
|
||||||
char* mimetype, char* name) {
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
guac_rdp_stream* rdp_stream;
|
|
||||||
guac_rdp_svc* svc = guac_rdp_get_svc(user->client, name);
|
|
||||||
|
|
||||||
/* Fail if no such SVC */
|
|
||||||
if (svc == NULL) {
|
|
||||||
guac_user_log(user, GUAC_LOG_ERROR,
|
|
||||||
"Requested non-existent pipe: \"%s\".",
|
|
||||||
name);
|
|
||||||
guac_protocol_send_ack(user->socket, stream, "FAIL (NO SUCH PIPE)",
|
|
||||||
GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST);
|
|
||||||
guac_socket_flush(user->socket);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
guac_user_log(user, GUAC_LOG_ERROR,
|
|
||||||
"Inbound half of channel \"%s\" connected.",
|
|
||||||
name);
|
|
||||||
|
|
||||||
/* Init stream data */
|
|
||||||
stream->data = rdp_stream = malloc(sizeof(guac_rdp_stream));
|
|
||||||
stream->blob_handler = guac_rdp_svc_blob_handler;
|
|
||||||
rdp_stream->type = GUAC_RDP_INBOUND_SVC_STREAM;
|
|
||||||
rdp_stream->svc = svc;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int guac_rdp_upload_blob_handler(guac_user* user, guac_stream* stream,
|
int guac_rdp_upload_blob_handler(guac_user* user, guac_stream* stream,
|
||||||
void* data, int length) {
|
void* data, int length) {
|
||||||
|
|
||||||
@ -201,23 +165,6 @@ int guac_rdp_upload_blob_handler(guac_user* user, guac_stream* stream,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int guac_rdp_svc_blob_handler(guac_user* user, guac_stream* stream,
|
|
||||||
void* data, int length) {
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;
|
|
||||||
|
|
||||||
/* Write blob data to SVC directly */
|
|
||||||
guac_rdp_svc_write(rdp_stream->svc, data, length);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
guac_protocol_send_ack(user->socket, stream, "OK (DATA RECEIVED)",
|
|
||||||
GUAC_PROTOCOL_STATUS_SUCCESS);
|
|
||||||
guac_socket_flush(user->socket);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int guac_rdp_upload_end_handler(guac_user* user, guac_stream* stream) {
|
int guac_rdp_upload_end_handler(guac_user* user, guac_stream* stream) {
|
||||||
|
|
||||||
guac_client* client = user->client;
|
guac_client* client = user->client;
|
||||||
|
@ -23,9 +23,6 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "common/json.h"
|
#include "common/json.h"
|
||||||
#if 0
|
|
||||||
#include "rdp_svc.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
#include <guacamole/protocol.h>
|
#include <guacamole/protocol.h>
|
||||||
@ -113,12 +110,7 @@ typedef enum guac_rdp_stream_type {
|
|||||||
/**
|
/**
|
||||||
* An in-progress stream of a directory listing.
|
* An in-progress stream of a directory listing.
|
||||||
*/
|
*/
|
||||||
GUAC_RDP_LS_STREAM,
|
GUAC_RDP_LS_STREAM
|
||||||
|
|
||||||
/**
|
|
||||||
* The inbound half of a static virtual channel.
|
|
||||||
*/
|
|
||||||
GUAC_RDP_INBOUND_SVC_STREAM
|
|
||||||
|
|
||||||
} guac_rdp_stream_type;
|
} guac_rdp_stream_type;
|
||||||
|
|
||||||
@ -147,13 +139,6 @@ typedef struct guac_rdp_stream {
|
|||||||
*/
|
*/
|
||||||
guac_rdp_ls_status ls_status;
|
guac_rdp_ls_status ls_status;
|
||||||
|
|
||||||
#if 0
|
|
||||||
/**
|
|
||||||
* Associated SVC instance. Only valid for GUAC_RDP_INBOUND_SVC_STREAM.
|
|
||||||
*/
|
|
||||||
guac_rdp_svc* svc;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} guac_rdp_stream;
|
} guac_rdp_stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,21 +146,11 @@ typedef struct guac_rdp_stream {
|
|||||||
*/
|
*/
|
||||||
guac_user_file_handler guac_rdp_upload_file_handler;
|
guac_user_file_handler guac_rdp_upload_file_handler;
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for inbound pipes related to static virtual channels.
|
|
||||||
*/
|
|
||||||
guac_user_pipe_handler guac_rdp_svc_pipe_handler;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for stream data related to file uploads.
|
* Handler for stream data related to file uploads.
|
||||||
*/
|
*/
|
||||||
guac_user_blob_handler guac_rdp_upload_blob_handler;
|
guac_user_blob_handler guac_rdp_upload_blob_handler;
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for stream data related to static virtual channels.
|
|
||||||
*/
|
|
||||||
guac_user_blob_handler guac_rdp_svc_blob_handler;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for end-of-stream related to file uploads.
|
* Handler for end-of-stream related to file uploads.
|
||||||
*/
|
*/
|
||||||
|
@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "client.h"
|
|
||||||
#include "common/list.h"
|
|
||||||
#include "rdp.h"
|
|
||||||
#include "rdp_svc.h"
|
|
||||||
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <guacamole/client.h>
|
|
||||||
#include <guacamole/string.h>
|
|
||||||
#include <winpr/stream.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
guac_rdp_svc* guac_rdp_alloc_svc(guac_client* client, char* name) {
|
|
||||||
|
|
||||||
guac_rdp_svc* svc = malloc(sizeof(guac_rdp_svc));
|
|
||||||
|
|
||||||
/* Init SVC */
|
|
||||||
svc->client = client;
|
|
||||||
svc->plugin = NULL;
|
|
||||||
svc->output_pipe = NULL;
|
|
||||||
|
|
||||||
/* Init name */
|
|
||||||
int name_length = guac_strlcpy(svc->name, name, GUAC_RDP_SVC_MAX_LENGTH);
|
|
||||||
|
|
||||||
/* Warn about name length */
|
|
||||||
if (name_length >= GUAC_RDP_SVC_MAX_LENGTH)
|
|
||||||
guac_client_log(client, GUAC_LOG_INFO,
|
|
||||||
"Static channel name \"%s\" exceeds maximum of %i characters "
|
|
||||||
"and will be truncated", name, GUAC_RDP_SVC_MAX_LENGTH - 1);
|
|
||||||
|
|
||||||
return svc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void guac_rdp_free_svc(guac_rdp_svc* svc) {
|
|
||||||
free(svc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void guac_rdp_svc_send_pipe(guac_socket* socket, guac_rdp_svc* svc) {
|
|
||||||
|
|
||||||
/* Send pipe instruction for the SVC's output stream */
|
|
||||||
guac_protocol_send_pipe(socket, svc->output_pipe,
|
|
||||||
"application/octet-stream", svc->name);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void guac_rdp_svc_send_pipes(guac_user* user) {
|
|
||||||
|
|
||||||
guac_client* client = user->client;
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
|
||||||
|
|
||||||
guac_common_list_lock(rdp_client->available_svc);
|
|
||||||
|
|
||||||
/* Send pipe for each allocated SVC's output stream */
|
|
||||||
guac_common_list_element* current = rdp_client->available_svc->head;
|
|
||||||
while (current != NULL) {
|
|
||||||
guac_rdp_svc_send_pipe(user->socket, (guac_rdp_svc*) current->data);
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
guac_common_list_unlock(rdp_client->available_svc);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void guac_rdp_add_svc(guac_client* client, guac_rdp_svc* svc) {
|
|
||||||
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
|
||||||
|
|
||||||
/* Add to list of available SVC */
|
|
||||||
guac_common_list_lock(rdp_client->available_svc);
|
|
||||||
guac_common_list_add(rdp_client->available_svc, svc);
|
|
||||||
guac_common_list_unlock(rdp_client->available_svc);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
guac_rdp_svc* guac_rdp_get_svc(guac_client* client, const char* name) {
|
|
||||||
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
|
||||||
guac_common_list_element* current;
|
|
||||||
guac_rdp_svc* found = NULL;
|
|
||||||
|
|
||||||
/* For each available SVC */
|
|
||||||
guac_common_list_lock(rdp_client->available_svc);
|
|
||||||
current = rdp_client->available_svc->head;
|
|
||||||
while (current != NULL) {
|
|
||||||
|
|
||||||
/* If name matches, found */
|
|
||||||
guac_rdp_svc* current_svc = (guac_rdp_svc*) current->data;
|
|
||||||
if (strcmp(current_svc->name, name) == 0) {
|
|
||||||
found = current_svc;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
current = current->next;
|
|
||||||
|
|
||||||
}
|
|
||||||
guac_common_list_unlock(rdp_client->available_svc);
|
|
||||||
|
|
||||||
return found;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
guac_rdp_svc* guac_rdp_remove_svc(guac_client* client, const char* name) {
|
|
||||||
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
|
||||||
guac_common_list_element* current;
|
|
||||||
guac_rdp_svc* found = NULL;
|
|
||||||
|
|
||||||
/* For each available SVC */
|
|
||||||
guac_common_list_lock(rdp_client->available_svc);
|
|
||||||
current = rdp_client->available_svc->head;
|
|
||||||
while (current != NULL) {
|
|
||||||
|
|
||||||
/* If name matches, remove entry */
|
|
||||||
guac_rdp_svc* current_svc = (guac_rdp_svc*) current->data;
|
|
||||||
if (strcmp(current_svc->name, name) == 0) {
|
|
||||||
guac_common_list_remove(rdp_client->available_svc, current);
|
|
||||||
found = current_svc;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
current = current->next;
|
|
||||||
|
|
||||||
}
|
|
||||||
guac_common_list_unlock(rdp_client->available_svc);
|
|
||||||
|
|
||||||
/* Return removed entry, if any */
|
|
||||||
return found;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void guac_rdp_svc_write(guac_rdp_svc* svc, void* data, int length) {
|
|
||||||
|
|
||||||
wStream* output_stream;
|
|
||||||
|
|
||||||
/* Do not write of plugin not associated */
|
|
||||||
if (svc->plugin == NULL) {
|
|
||||||
guac_client_log(svc->client, GUAC_LOG_ERROR,
|
|
||||||
"Channel \"%s\" output dropped.",
|
|
||||||
svc->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build packet */
|
|
||||||
output_stream = Stream_New(NULL, length);
|
|
||||||
Stream_Write(output_stream, data, length);
|
|
||||||
|
|
||||||
/* Send packet */
|
|
||||||
svc_plugin_send(svc->plugin, output_stream);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __GUAC_RDP_RDP_SVC_H
|
|
||||||
#define __GUAC_RDP_RDP_SVC_H
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <guacamole/client.h>
|
|
||||||
#include <guacamole/stream.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum number of bytes to allow within each channel name, including
|
|
||||||
* null terminator.
|
|
||||||
*/
|
|
||||||
#define GUAC_RDP_SVC_MAX_LENGTH 8
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure describing a static virtual channel, and the corresponding
|
|
||||||
* Guacamole pipes.
|
|
||||||
*/
|
|
||||||
typedef struct guac_rdp_svc {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to the client owning this static channel.
|
|
||||||
*/
|
|
||||||
guac_client* client;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to associated SVC plugin.
|
|
||||||
*/
|
|
||||||
rdpSvcPlugin* plugin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the RDP channel in use, and the name to use for each pipe.
|
|
||||||
*/
|
|
||||||
char name[GUAC_RDP_SVC_MAX_LENGTH];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The output pipe, opened when the RDP server receives a connection to
|
|
||||||
* the static channel.
|
|
||||||
*/
|
|
||||||
guac_stream* output_pipe;
|
|
||||||
|
|
||||||
} guac_rdp_svc;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate a new SVC with the given name.
|
|
||||||
*
|
|
||||||
* @param client
|
|
||||||
* The guac_client associated with the current RDP session.
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* The name of the virtual channel to allocate.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* A newly-allocated static virtual channel.
|
|
||||||
*/
|
|
||||||
guac_rdp_svc* guac_rdp_alloc_svc(guac_client* client, char* name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free the given SVC.
|
|
||||||
*
|
|
||||||
* @param svc
|
|
||||||
* The static virtual channel to free.
|
|
||||||
*/
|
|
||||||
void guac_rdp_free_svc(guac_rdp_svc* svc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends the "pipe" instruction describing the given static virtual channel
|
|
||||||
* along the given socket. This pipe instruction will relate the SVC's
|
|
||||||
* underlying output stream with the SVC's name and the mimetype
|
|
||||||
* "application/octet-stream".
|
|
||||||
*
|
|
||||||
* @param socket
|
|
||||||
* The socket along which the "pipe" instruction should be sent.
|
|
||||||
*
|
|
||||||
* @param svc
|
|
||||||
* The static virtual channel that the "pipe" instruction should describe.
|
|
||||||
*/
|
|
||||||
void guac_rdp_svc_send_pipe(guac_socket* socket, guac_rdp_svc* svc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends the "pipe" instructions describing all static virtual channels
|
|
||||||
* available to the given user along that user's socket. Each pipe instruction
|
|
||||||
* will relate the associated SVC's underlying output stream with the SVC's
|
|
||||||
* name and the mimetype "application/octet-stream".
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* The user to send the "pipe" instructions to.
|
|
||||||
*/
|
|
||||||
void guac_rdp_svc_send_pipes(guac_user* user);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the given SVC to the list of all available SVCs.
|
|
||||||
*
|
|
||||||
* @param client
|
|
||||||
* The guac_client associated with the current RDP session.
|
|
||||||
*
|
|
||||||
* @param svc
|
|
||||||
* The static virtual channel to add to the list of all such channels
|
|
||||||
* available.
|
|
||||||
*/
|
|
||||||
void guac_rdp_add_svc(guac_client* client, guac_rdp_svc* svc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the SVC with the given name from the list stored in the client.
|
|
||||||
*
|
|
||||||
* @param client
|
|
||||||
* The guac_client associated with the current RDP session.
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* The name of the static virtual channel to retrieve.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The static virtual channel with the given name, or NULL if no such
|
|
||||||
* virtual channel exists.
|
|
||||||
*/
|
|
||||||
guac_rdp_svc* guac_rdp_get_svc(guac_client* client, const char* name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the SVC with the given name from the list stored in the client.
|
|
||||||
*
|
|
||||||
* @param client
|
|
||||||
* The guac_client associated with the current RDP session.
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* The name of the static virtual channel to remove.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The static virtual channel that was removed, or NULL if no such virtual
|
|
||||||
* channel exists.
|
|
||||||
*/
|
|
||||||
guac_rdp_svc* guac_rdp_remove_svc(guac_client* client, const char* name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write the given blob of data to the virtual channel.
|
|
||||||
*
|
|
||||||
* @param svc
|
|
||||||
* The static virtual channel to write data to.
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* The data to write.
|
|
||||||
*
|
|
||||||
* @param length
|
|
||||||
* The number of bytes to write.
|
|
||||||
*/
|
|
||||||
void guac_rdp_svc_write(guac_rdp_svc* svc, void* data, int length);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
227
src/protocols/rdp/svc.c
Normal file
227
src/protocols/rdp/svc.c
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "channels.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "common/list.h"
|
||||||
|
#include "rdp.h"
|
||||||
|
#include "svc.h"
|
||||||
|
|
||||||
|
#include <freerdp/svc.h>
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/string.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
|
#include <winpr/wtsapi.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void guac_rdp_svc_send_pipe(guac_socket* socket, guac_rdp_svc* svc) {
|
||||||
|
|
||||||
|
/* Send pipe instruction for the SVC's output stream */
|
||||||
|
guac_protocol_send_pipe(socket, svc->output_pipe,
|
||||||
|
"application/octet-stream", svc->channel_def.name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_rdp_svc_send_pipes(guac_user* user) {
|
||||||
|
|
||||||
|
guac_client* client = user->client;
|
||||||
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
|
||||||
|
guac_common_list_lock(rdp_client->available_svc);
|
||||||
|
|
||||||
|
/* Send pipe for each allocated SVC's output stream */
|
||||||
|
guac_common_list_element* current = rdp_client->available_svc->head;
|
||||||
|
while (current != NULL) {
|
||||||
|
guac_rdp_svc_send_pipe(user->socket, (guac_rdp_svc*) current->data);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
guac_common_list_unlock(rdp_client->available_svc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_rdp_svc_add(guac_client* client, guac_rdp_svc* svc) {
|
||||||
|
|
||||||
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
|
||||||
|
/* Add to list of available SVC */
|
||||||
|
guac_common_list_lock(rdp_client->available_svc);
|
||||||
|
guac_common_list_add(rdp_client->available_svc, svc);
|
||||||
|
guac_common_list_unlock(rdp_client->available_svc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
guac_rdp_svc* guac_rdp_svc_get(guac_client* client, const char* name) {
|
||||||
|
|
||||||
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
guac_common_list_element* current;
|
||||||
|
guac_rdp_svc* found = NULL;
|
||||||
|
|
||||||
|
/* For each available SVC */
|
||||||
|
guac_common_list_lock(rdp_client->available_svc);
|
||||||
|
current = rdp_client->available_svc->head;
|
||||||
|
while (current != NULL) {
|
||||||
|
|
||||||
|
/* If name matches, found */
|
||||||
|
guac_rdp_svc* current_svc = (guac_rdp_svc*) current->data;
|
||||||
|
if (strcmp(current_svc->channel_def.name, name) == 0) {
|
||||||
|
found = current_svc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
|
||||||
|
}
|
||||||
|
guac_common_list_unlock(rdp_client->available_svc);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
guac_rdp_svc* guac_rdp_svc_remove(guac_client* client, const char* name) {
|
||||||
|
|
||||||
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
guac_common_list_element* current;
|
||||||
|
guac_rdp_svc* found = NULL;
|
||||||
|
|
||||||
|
/* For each available SVC */
|
||||||
|
guac_common_list_lock(rdp_client->available_svc);
|
||||||
|
current = rdp_client->available_svc->head;
|
||||||
|
while (current != NULL) {
|
||||||
|
|
||||||
|
/* If name matches, remove entry */
|
||||||
|
guac_rdp_svc* current_svc = (guac_rdp_svc*) current->data;
|
||||||
|
if (strcmp(current_svc->channel_def.name, name) == 0) {
|
||||||
|
guac_common_list_remove(rdp_client->available_svc, current);
|
||||||
|
found = current_svc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
|
||||||
|
}
|
||||||
|
guac_common_list_unlock(rdp_client->available_svc);
|
||||||
|
|
||||||
|
/* Return removed entry, if any */
|
||||||
|
return found;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_rdp_svc_write(guac_rdp_svc* svc, void* data, int length) {
|
||||||
|
|
||||||
|
/* Do not write of plugin not associated */
|
||||||
|
if (!svc->open_handle) {
|
||||||
|
guac_client_log(svc->client, GUAC_LOG_WARNING, "%i bytes of data "
|
||||||
|
"received from the Guacamole client for SVC \"%s\" are being "
|
||||||
|
"dropped because the remote desktop side of that SVC is "
|
||||||
|
"connected.", length, svc->channel_def.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FreeRDP_VirtualChannelWriteEx() assumes that sent data is dynamically
|
||||||
|
* allocated and will free() the data after it is sent */
|
||||||
|
void* data_copy = malloc(length);
|
||||||
|
memcpy(data_copy, data, length);
|
||||||
|
|
||||||
|
/* Send received data */
|
||||||
|
svc->entry_points.pVirtualChannelWriteEx(svc->init_handle,
|
||||||
|
svc->open_handle, data_copy, length,
|
||||||
|
NULL /* NOTE: If non-NULL, this MUST be a pointer to a wStream
|
||||||
|
containing the supplied buffer, and that wStream will be
|
||||||
|
automatically freed when FreeRDP handles the write */);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_rdp_svc_pipe_handler(guac_user* user, guac_stream* stream,
|
||||||
|
char* mimetype, char* name) {
|
||||||
|
|
||||||
|
guac_rdp_svc* svc = guac_rdp_svc_get(user->client, name);
|
||||||
|
|
||||||
|
/* Fail if no such SVC */
|
||||||
|
if (svc == NULL) {
|
||||||
|
guac_user_log(user, GUAC_LOG_WARNING, "User requested non-existent "
|
||||||
|
"pipe (no such SVC configured): \"%s\"", name);
|
||||||
|
guac_protocol_send_ack(user->socket, stream, "FAIL (NO SUCH PIPE)",
|
||||||
|
GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST);
|
||||||
|
guac_socket_flush(user->socket);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
guac_user_log(user, GUAC_LOG_DEBUG, "Inbound half of channel \"%s\" "
|
||||||
|
"connected.", name);
|
||||||
|
|
||||||
|
/* Init stream data */
|
||||||
|
stream->data = svc;
|
||||||
|
stream->blob_handler = guac_rdp_svc_blob_handler;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_rdp_svc_blob_handler(guac_user* user, guac_stream* stream,
|
||||||
|
void* data, int length) {
|
||||||
|
|
||||||
|
/* Write blob data to SVC directly */
|
||||||
|
guac_rdp_svc* svc = (guac_rdp_svc*) stream->data;
|
||||||
|
guac_rdp_svc_write(svc, data, length);
|
||||||
|
|
||||||
|
guac_protocol_send_ack(user->socket, stream, "OK (DATA RECEIVED)",
|
||||||
|
GUAC_PROTOCOL_STATUS_SUCCESS);
|
||||||
|
guac_socket_flush(user->socket);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_rdp_svc_load_plugin(rdpContext* context, char* name) {
|
||||||
|
|
||||||
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
|
guac_rdp_svc* svc = calloc(1, sizeof(guac_rdp_svc));
|
||||||
|
svc->client = client;
|
||||||
|
|
||||||
|
/* Init FreeRDP channel definition */
|
||||||
|
int name_length = guac_strlcpy(svc->channel_def.name, name, GUAC_RDP_SVC_MAX_LENGTH);
|
||||||
|
svc->channel_def.options = CHANNEL_OPTION_INITIALIZED
|
||||||
|
| CHANNEL_OPTION_ENCRYPT_RDP
|
||||||
|
| CHANNEL_OPTION_COMPRESS_RDP;
|
||||||
|
|
||||||
|
/* Warn about name length */
|
||||||
|
if (name_length >= GUAC_RDP_SVC_MAX_LENGTH)
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING,
|
||||||
|
"Static channel name \"%s\" exceeds maximum length of %i "
|
||||||
|
"characters and will be truncated to \"%s\".",
|
||||||
|
name, GUAC_RDP_SVC_MAX_LENGTH - 1, svc->channel_def.name);
|
||||||
|
|
||||||
|
/* Attempt to load guacsvc plugin for new static channel */
|
||||||
|
if (guac_freerdp_channels_load_plugin(context->channels, context->settings, "guacsvc", svc)) {
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING, "Cannot create static "
|
||||||
|
"channel \"%s\": failed to load guacsvc plugin.",
|
||||||
|
svc->channel_def.name);
|
||||||
|
free(svc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store and log on success (SVC structure will be freed on channel termination) */
|
||||||
|
else
|
||||||
|
guac_client_log(client, GUAC_LOG_INFO, "Created static channel "
|
||||||
|
"\"%s\"...", svc->channel_def.name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
215
src/protocols/rdp/svc.h
Normal file
215
src/protocols/rdp/svc.h
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GUAC_RDP_SVC_H
|
||||||
|
#define GUAC_RDP_SVC_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <freerdp/svc.h>
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/stream.h>
|
||||||
|
#include <winpr/wtsapi.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of bytes to allow within each channel name, including
|
||||||
|
* null terminator.
|
||||||
|
*/
|
||||||
|
#define GUAC_RDP_SVC_MAX_LENGTH 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure describing a static virtual channel, and the corresponding
|
||||||
|
* Guacamole pipes and FreeRDP resources.
|
||||||
|
*/
|
||||||
|
typedef struct guac_rdp_svc {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to the client owning this static channel.
|
||||||
|
*/
|
||||||
|
guac_client* client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output pipe, opened when the RDP server receives a connection to
|
||||||
|
* the static channel.
|
||||||
|
*/
|
||||||
|
guac_stream* output_pipe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition of this static virtual channel, including its name. The
|
||||||
|
* name of the SVC is also used as the name of the associated Guacamole
|
||||||
|
* pipe streams.
|
||||||
|
*/
|
||||||
|
CHANNEL_DEF channel_def;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions and data specific to the FreeRDP side of the virtual channel
|
||||||
|
* and plugin.
|
||||||
|
*/
|
||||||
|
CHANNEL_ENTRY_POINTS_FREERDP_EX entry_points;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle which identifies the client connection, typically referred to
|
||||||
|
* within the FreeRDP source as pInitHandle. This handle is provided to the
|
||||||
|
* channel entry point and the channel init event handler. The handle must
|
||||||
|
* eventually be used within the channel open event handler to obtain a
|
||||||
|
* handle to the channel itself.
|
||||||
|
*/
|
||||||
|
PVOID init_handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle which identifies the channel itself, typically referred to within
|
||||||
|
* the FreeRDP source as OpenHandle. This handle is obtained through a call
|
||||||
|
* to entry_points.pVirtualChannelOpenEx() in response to receiving a
|
||||||
|
* CHANNEL_EVENT_CONNECTED event via the init event handler.
|
||||||
|
*
|
||||||
|
* Data is received in CHANNEL_EVENT_DATA_RECEIVED events via the open
|
||||||
|
* event handler, and data is written through calls to
|
||||||
|
* entry_points.pVirtualChannelWriteEx().
|
||||||
|
*/
|
||||||
|
DWORD open_handle;
|
||||||
|
|
||||||
|
} guac_rdp_svc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes arbitrary static virtual channel (SVC) support for RDP, loading
|
||||||
|
* a new instance of Guacamole's arbitrary SVC plugin for FreeRDP ("guacsvc")
|
||||||
|
* supporting the channel having the given name. Data sent from within the RDP
|
||||||
|
* session using this channel will be sent along an identically-named pipe
|
||||||
|
* stream to the Guacamole client, and data sent along a pipe stream having the
|
||||||
|
* same name will be written to the SVC and received within the RDP session. If
|
||||||
|
* failures occur while loading the plugin, messages noting the specifics of
|
||||||
|
* those failures will be logged, and support for the given channel will not be
|
||||||
|
* functional.
|
||||||
|
*
|
||||||
|
* This MUST be called within the PreConnect callback of the freerdp instance
|
||||||
|
* for static virtual channel support to be loaded.
|
||||||
|
*
|
||||||
|
* @param rdpContext
|
||||||
|
* The rdpContext associated with the FreeRDP side of the RDP connection.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the SVC which should be handled by the new instance of the
|
||||||
|
* plugin.
|
||||||
|
*/
|
||||||
|
void guac_rdp_svc_load_plugin(rdpContext* context, char* name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the "pipe" instruction describing the given static virtual channel
|
||||||
|
* along the given socket. This pipe instruction will relate the SVC's
|
||||||
|
* underlying output stream with the SVC's name and the mimetype
|
||||||
|
* "application/octet-stream".
|
||||||
|
*
|
||||||
|
* @param socket
|
||||||
|
* The socket along which the "pipe" instruction should be sent.
|
||||||
|
*
|
||||||
|
* @param svc
|
||||||
|
* The static virtual channel that the "pipe" instruction should describe.
|
||||||
|
*/
|
||||||
|
void guac_rdp_svc_send_pipe(guac_socket* socket, guac_rdp_svc* svc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the "pipe" instructions describing all static virtual channels
|
||||||
|
* available to the given user along that user's socket. Each pipe instruction
|
||||||
|
* will relate the associated SVC's underlying output stream with the SVC's
|
||||||
|
* name and the mimetype "application/octet-stream".
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user to send the "pipe" instructions to.
|
||||||
|
*/
|
||||||
|
void guac_rdp_svc_send_pipes(guac_user* user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given SVC to the list of all available SVCs. This function must be
|
||||||
|
* invoked after the SVC is connected for inbound pipe streams having that
|
||||||
|
* SVC's name to result in received data being sent into the RDP session.
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The guac_client associated with the current RDP session.
|
||||||
|
*
|
||||||
|
* @param svc
|
||||||
|
* The static virtual channel to add to the list of all such channels
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
void guac_rdp_svc_add(guac_client* client, guac_rdp_svc* svc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the SVC with the given name from the list stored in the client. The
|
||||||
|
* requested SVC must previously have been added using guac_rdp_svc_add().
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The guac_client associated with the current RDP session.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the static virtual channel to retrieve.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The static virtual channel with the given name, or NULL if no such
|
||||||
|
* virtual channel exists.
|
||||||
|
*/
|
||||||
|
guac_rdp_svc* guac_rdp_svc_get(guac_client* client, const char* name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the SVC with the given name from the list stored in the client.
|
||||||
|
* Inbound pipe streams having the given name will no longer be routed to the
|
||||||
|
* associated SVC.
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The guac_client associated with the current RDP session.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the static virtual channel to remove.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The static virtual channel that was removed, or NULL if no such virtual
|
||||||
|
* channel exists.
|
||||||
|
*/
|
||||||
|
guac_rdp_svc* guac_rdp_svc_remove(guac_client* client, const char* name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the given blob of data to the virtual channel such that it can be
|
||||||
|
* received within the RDP session.
|
||||||
|
*
|
||||||
|
* @param svc
|
||||||
|
* The static virtual channel to write data to.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* The data to write.
|
||||||
|
*
|
||||||
|
* @param length
|
||||||
|
* The number of bytes to write.
|
||||||
|
*/
|
||||||
|
void guac_rdp_svc_write(guac_rdp_svc* svc, void* data, int length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for "blob" instructions which automatically writes received data to
|
||||||
|
* the associated SVC using guac_rdp_svc_write().
|
||||||
|
*/
|
||||||
|
guac_user_blob_handler guac_rdp_svc_blob_handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for "pipe" instructions which automatically prepares received pipe
|
||||||
|
* streams to automatically write received blobs to the SVC having the same
|
||||||
|
* name as the pipe stream. Received pipe streams are associated with the
|
||||||
|
* relevant guac_rdp_svc instance and the SVC-specific "blob" instructino
|
||||||
|
* handler (guac_rdp_svc_blob_handler).
|
||||||
|
*/
|
||||||
|
guac_user_pipe_handler guac_rdp_svc_pipe_handler;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -26,9 +26,7 @@
|
|||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
#include "rdp_settings.h"
|
#include "rdp_settings.h"
|
||||||
#include "rdp_stream.h"
|
#include "rdp_stream.h"
|
||||||
#if 0
|
#include "svc.h"
|
||||||
#include "rdp_svc.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_COMMON_SSH
|
#ifdef ENABLE_COMMON_SSH
|
||||||
#include "sftp.h"
|
#include "sftp.h"
|
||||||
@ -87,10 +85,8 @@ int guac_rdp_user_join_handler(guac_user* user, int argc, char** argv) {
|
|||||||
if (rdp_client->audio)
|
if (rdp_client->audio)
|
||||||
guac_audio_stream_add_user(rdp_client->audio, user);
|
guac_audio_stream_add_user(rdp_client->audio, user);
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Bring user up to date with any registered static channels */
|
/* Bring user up to date with any registered static channels */
|
||||||
guac_rdp_svc_send_pipes(user);
|
guac_rdp_svc_send_pipes(user);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Synchronize with current display */
|
/* Synchronize with current display */
|
||||||
guac_common_display_dup(rdp_client->display, user, user->socket);
|
guac_common_display_dup(rdp_client->display, user, user->socket);
|
||||||
@ -112,10 +108,8 @@ int guac_rdp_user_join_handler(guac_user* user, int argc, char** argv) {
|
|||||||
/* Set generic (non-filesystem) file upload handler */
|
/* Set generic (non-filesystem) file upload handler */
|
||||||
user->file_handler = guac_rdp_user_file_handler;
|
user->file_handler = guac_rdp_user_file_handler;
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Inbound arbitrary named pipes */
|
/* Inbound arbitrary named pipes */
|
||||||
user->pipe_handler = guac_rdp_svc_pipe_handler;
|
user->pipe_handler = guac_rdp_svc_pipe_handler;
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user