From a1ec5d9ad732053f6fb729c5816bee8398197e34 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sat, 24 Mar 2018 16:22:55 -0400 Subject: [PATCH] GUACAMOLE-445: Implement per-device announce stream, set it up with device initalization, and collect them all during the annonuce process. --- .../rdp/guac_rdpdr/rdpdr_fs_service.c | 33 ++++----- src/protocols/rdp/guac_rdpdr/rdpdr_messages.c | 25 +++++-- src/protocols/rdp/guac_rdpdr/rdpdr_printer.c | 70 ++++++++++--------- src/protocols/rdp/guac_rdpdr/rdpdr_printer.h | 7 ++ src/protocols/rdp/guac_rdpdr/rdpdr_service.h | 27 +++++-- 5 files changed, 99 insertions(+), 63 deletions(-) diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_service.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_service.c index fb82996f..85787db2 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_service.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_service.c @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef ENABLE_WINPR #include @@ -36,21 +37,6 @@ #include "compat/winpr-stream.h" #endif -static void guac_rdpdr_device_fs_announce_handler(guac_rdpdr_device* device, - wStream* output_stream, int device_id) { - - /* Filesystem header */ - guac_client_log(device->rdpdr->client, GUAC_LOG_INFO, "Sending filesystem"); - Stream_Write_UINT32(output_stream, RDPDR_DTYP_FILESYSTEM); - Stream_Write_UINT32(output_stream, device_id); - Stream_Write(output_stream, "GUAC\0\0\0\0", 8); /* DOS name */ - - /* Filesystem data */ - Stream_Write_UINT32(output_stream, GUAC_FILESYSTEM_NAME_LENGTH); - Stream_Write(output_stream, GUAC_FILESYSTEM_NAME, GUAC_FILESYSTEM_NAME_LENGTH); - -} - static void guac_rdpdr_device_fs_iorequest_handler(guac_rdpdr_device* device, wStream* input_stream, int file_id, int completion_id, int major_func, int minor_func) { @@ -128,6 +114,9 @@ static void guac_rdpdr_device_fs_iorequest_handler(guac_rdpdr_device* device, } static void guac_rdpdr_device_fs_free_handler(guac_rdpdr_device* device) { + + Stream_Free(device->device_announce, 1); + } void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr) { @@ -143,9 +132,21 @@ void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr) { device->rdpdr = rdpdr; device->device_id = id; device->device_name = "Guacamole Filesystem"; + int device_name_len = guac_utf8_strlen(device->device_name); + device->device_type = RDPDR_DTYP_FILESYSTEM; + device->dos_name = "GUACFS\0\0"; + + /* Set up the device announcement */ + device->device_announce_len = 20 + device_name_len; + device->device_announce = Stream_New(NULL, device->device_announce_len); + Stream_Write_UINT32(device->device_announce, device->device_type); + Stream_Write_UINT32(device->device_announce, device->device_id); + Stream_Write(device->device_announce, device->dos_name, 8); + Stream_Write_UINT32(device->device_announce, device_name_len); + Stream_Write(device->device_announce, device->device_name, device_name_len); + /* Set handlers */ - device->announce_handler = guac_rdpdr_device_fs_announce_handler; device->iorequest_handler = guac_rdpdr_device_fs_iorequest_handler; device->free_handler = guac_rdpdr_device_fs_free_handler; diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c b/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c index 7bc9f3b2..66626adb 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c @@ -22,9 +22,11 @@ #include "rdp.h" #include "rdpdr_messages.h" #include "rdpdr_service.h" +#include "unicode.h" #include #include +#include #ifdef ENABLE_WINPR #include @@ -122,20 +124,29 @@ static void guac_rdpdr_send_client_capability(guac_rdpdrPlugin* rdpdr) { static void guac_rdpdr_send_client_device_list_announce_request(guac_rdpdrPlugin* rdpdr) { - int i; - wStream* output_stream = Stream_New(NULL, 256); + /* Calculate number of bytes needed for the stream */ + int streamBytes = 16; + for (int i=0; i < rdpdr->devices_registered; i++) + streamBytes += rdpdr->devices[i].device_announce_len; + + /* Allocate the stream */ + wStream* output_stream = Stream_New(NULL, streamBytes); /* Write header */ Stream_Write_UINT16(output_stream, RDPDR_CTYP_CORE); Stream_Write_UINT16(output_stream, PAKID_CORE_DEVICELIST_ANNOUNCE); - /* List devices */ + /* Get the stream for each of the devices. */ Stream_Write_UINT32(output_stream, rdpdr->devices_registered); - for (i=0; idevices_registered; i++) { - guac_rdpdr_device* device = &(rdpdr->devices[i]); - device->announce_handler(device, output_stream, i); + for (int i=0; idevices_registered; i++) { + + Stream_Write(output_stream, + Stream_Buffer(rdpdr->devices[i].device_announce), + rdpdr->devices[i].device_announce_len); + guac_client_log(rdpdr->client, GUAC_LOG_INFO, "Registered device %i (%s)", - device->device_id, device->device_name); + rdpdr->devices[i].device_id, rdpdr->devices[i].device_name); + } svc_plugin_send((rdpSvcPlugin*) rdpdr, output_stream); diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c index 055288a5..ace025c4 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c @@ -133,38 +133,6 @@ void guac_rdpdr_process_print_job_close(guac_rdpdr_device* device, } -static void guac_rdpdr_device_printer_announce_handler(guac_rdpdr_device* device, - wStream* output_stream, int device_id) { - - /* Printer header */ - guac_client_log(device->rdpdr->client, GUAC_LOG_INFO, "Sending printer"); - Stream_Write_UINT32(output_stream, RDPDR_DTYP_PRINT); - Stream_Write_UINT32(output_stream, device_id); - Stream_Write(output_stream, "PRN1\0\0\0\0", 8); /* DOS name */ - - /* Printer data */ - int settings_length = guac_utf8_strlen(device->device_name); - int printer_name_length = (settings_length + 1) * 2; - char printer_name[printer_name_length]; - guac_rdp_utf8_to_utf16((const unsigned char*)device->device_name, - settings_length, printer_name, printer_name_length); - printer_name[printer_name_length - 2] = '\0'; - printer_name[printer_name_length - 1] = '\0'; - Stream_Write_UINT32(output_stream, 24 + GUAC_PRINTER_DRIVER_LENGTH + printer_name_length); - Stream_Write_UINT32(output_stream, - RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER - | RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER); - Stream_Write_UINT32(output_stream, 0); /* reserved - must be 0 */ - Stream_Write_UINT32(output_stream, 0); /* PnPName length (PnPName is ultimately ignored) */ - Stream_Write_UINT32(output_stream, GUAC_PRINTER_DRIVER_LENGTH); /* DriverName length */ - Stream_Write_UINT32(output_stream, printer_name_length); /* PrinterName length */ - Stream_Write_UINT32(output_stream, 0); /* CachedFields length */ - - Stream_Write(output_stream, GUAC_PRINTER_DRIVER, GUAC_PRINTER_DRIVER_LENGTH); - Stream_Write(output_stream, printer_name, printer_name_length); - -} - static void guac_rdpdr_device_printer_iorequest_handler(guac_rdpdr_device* device, wStream* input_stream, int file_id, int completion_id, int major_func, int minor_func) { @@ -196,7 +164,9 @@ static void guac_rdpdr_device_printer_iorequest_handler(guac_rdpdr_device* devic } static void guac_rdpdr_device_printer_free_handler(guac_rdpdr_device* device) { - /* Do nothing */ + + Stream_Free(device->device_announce, 1); + } void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name) { @@ -210,9 +180,41 @@ void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name) { device->rdpdr = rdpdr; device->device_id = id; device->device_name = printer_name; + int device_name_len = guac_utf8_strlen(device->device_name); + device->device_type = RDPDR_DTYP_PRINT; + device->dos_name = "PRN1\0\0\0\0"; + + /* Set up device announce stream */ + int prt_name_len = (device_name_len + 1) * 2; + device->device_announce_len = 44 + prt_name_len + + GUAC_PRINTER_DRIVER_LENGTH; + device->device_announce = Stream_New(NULL, device->device_announce_len); + + /* Write common information. */ + Stream_Write_UINT32(device->device_announce, device->device_type); + Stream_Write_UINT32(device->device_announce, device->device_id); + Stream_Write(device->device_announce, device->dos_name, 8); + + /* DeviceDataLength */ + Stream_Write_UINT32(device->device_announce, 24 + prt_name_len + GUAC_PRINTER_DRIVER_LENGTH); + + /* Begin printer-specific information */ + Stream_Write_UINT32(device->device_announce, + RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER + | RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER); /* Printer flags */ + Stream_Write_UINT32(device->device_announce, 0); /* Reserved - must be 0. */ + Stream_Write_UINT32(device->device_announce, 0); /* PnPName Length - ignored. */ + Stream_Write_UINT32(device->device_announce, GUAC_PRINTER_DRIVER_LENGTH); + Stream_Write_UINT32(device->device_announce, prt_name_len); + Stream_Write_UINT32(device->device_announce, 0); /* CachedFields length. */ + + Stream_Write(device->device_announce, GUAC_PRINTER_DRIVER, GUAC_PRINTER_DRIVER_LENGTH); + guac_rdp_utf8_to_utf16((const unsigned char*) device->device_name, + device_name_len + 1, (char*) Stream_Pointer(device->device_announce), + prt_name_len); + Stream_Seek(device->device_announce, prt_name_len); /* Set handlers */ - device->announce_handler = guac_rdpdr_device_printer_announce_handler; device->iorequest_handler = guac_rdpdr_device_printer_iorequest_handler; device->free_handler = guac_rdpdr_device_printer_free_handler; diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.h b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.h index 3d48dad9..9dbeb42c 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.h +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.h @@ -34,6 +34,13 @@ /** * Registers a new printer device within the RDPDR plugin. This must be done * before RDPDR connection finishes. + * + * @param rdpdr + * The RDP device redirection plugin where the device is registered. + * + * @param printer_name + * The name of the printer that will be registered with the RDP + * connection and passed through to the server. */ void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name); diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_service.h b/src/protocols/rdp/guac_rdpdr/rdpdr_service.h index 782d8b5d..ea5cb577 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_service.h +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_service.h @@ -74,15 +74,30 @@ struct guac_rdpdr_device { int device_id; /** - * An arbitrary device name, used for logging purposes only. + * Device name, used for logging and for passthrough to the + * server. */ const char* device_name; /** - * Handler which will be called when the RDPDR plugin is forming the client - * device announce list. + * The type of RDPDR device that this represents. */ - guac_rdpdr_device_announce_handler* announce_handler; + uint32_t device_type; + + /** + * The DOS name of the device. Max 8 bytes, including terminator. + */ + const char *dos_name; + + /** + * The stream that stores the RDPDR device announcement for this device. + */ + wStream* device_announce; + + /** + * The length of the device_announce wStream. + */ + int device_announce_len; /** * Handler which should be called for every I/O request received. @@ -90,7 +105,7 @@ struct guac_rdpdr_device { guac_rdpdr_device_iorequest_handler* iorequest_handler; /** - * Handlel which should be called when the device is being free'd. + * Handler which should be called when the device is being freed. */ guac_rdpdr_device_free_handler* free_handler; @@ -154,7 +169,7 @@ void guac_rdpdr_process_terminate(rdpSvcPlugin* plugin); void guac_rdpdr_process_event(rdpSvcPlugin* plugin, wMessage* event); /** - * Creates a new stream which contains the ommon DR_DEVICE_IOCOMPLETION header + * Creates a new stream which contains the common DR_DEVICE_IOCOMPLETION header * used for virtually all responses. */ wStream* guac_rdpdr_new_io_completion(guac_rdpdr_device* device,