From b21f00c29dc5dd100fad1a55bf88e267ca4b0add Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Fri, 23 Feb 2018 05:03:34 -0500 Subject: [PATCH 1/3] GUACAMOLE-445: Add settings for printer name. --- src/protocols/rdp/rdp_settings.c | 11 +++++++++++ src/protocols/rdp/rdp_settings.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/src/protocols/rdp/rdp_settings.c b/src/protocols/rdp/rdp_settings.c index 35f7f202..0ce3e846 100644 --- a/src/protocols/rdp/rdp_settings.c +++ b/src/protocols/rdp/rdp_settings.c @@ -52,6 +52,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { "color-depth", "disable-audio", "enable-printing", + "printer-name", "enable-drive", "drive-path", "create-drive-path", @@ -186,6 +187,11 @@ enum RDP_ARGS_IDX { */ IDX_ENABLE_PRINTING, + /** + * The name of the printer that will be passed through to the RDP server. + */ + IDX_PRINTER_NAME, + /** * "true" if the virtual drive should be enabled, "false" or blank * otherwise. @@ -788,6 +794,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, IDX_ENABLE_PRINTING, 0); + /* Name of redirected printer */ + settings->printer_name = + guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_PRINTER_NAME, "Guacamole Printer"); + /* Drive enable/disable */ settings->drive_enabled = guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, diff --git a/src/protocols/rdp/rdp_settings.h b/src/protocols/rdp/rdp_settings.h index ad71ca06..de2bd17e 100644 --- a/src/protocols/rdp/rdp_settings.h +++ b/src/protocols/rdp/rdp_settings.h @@ -177,6 +177,11 @@ typedef struct guac_rdp_settings { */ int printing_enabled; + /** + * Name of the redirected printer. + */ + char* printer_name; + /** * Whether the virtual drive is enabled. */ From e68fe8193856e556071756811d22dfa09294a750 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Fri, 23 Feb 2018 05:34:44 -0500 Subject: [PATCH 2/3] GUACAMOLE-445: Pass printer name from settings to RDP session. --- src/protocols/rdp/guac_rdpdr/rdpdr_messages.c | 1 - src/protocols/rdp/guac_rdpdr/rdpdr_messages.h | 6 ------ src/protocols/rdp/guac_rdpdr/rdpdr_printer.c | 19 ++++++++++++++----- src/protocols/rdp/guac_rdpdr/rdpdr_printer.h | 2 +- src/protocols/rdp/guac_rdpdr/rdpdr_service.c | 2 +- src/protocols/rdp/rdp_settings.c | 1 + 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c b/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c index fc9cd0f8..7bc9f3b2 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c @@ -273,4 +273,3 @@ void guac_rdpdr_process_prn_cache_data(guac_rdpdrPlugin* rdpdr, wStream* input_s void guac_rdpdr_process_prn_using_xps(guac_rdpdrPlugin* rdpdr, wStream* input_stream) { guac_client_log(rdpdr->client, GUAC_LOG_INFO, "Printer unexpectedly switched to XPS mode"); } - diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_messages.h b/src/protocols/rdp/guac_rdpdr/rdpdr_messages.h index 24a25938..8f276524 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_messages.h +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_messages.h @@ -76,12 +76,6 @@ #define GUAC_PRINTER_DRIVER "M\0S\0 \0P\0u\0b\0l\0i\0s\0h\0e\0r\0 \0I\0m\0a\0g\0e\0s\0e\0t\0t\0e\0r\0\0\0" #define GUAC_PRINTER_DRIVER_LENGTH 50 -/** - * Name of the printer itself. - */ -#define GUAC_PRINTER_NAME "G\0u\0a\0c\0a\0m\0o\0l\0e\0\0\0" -#define GUAC_PRINTER_NAME_LENGTH 20 - /** * Name of the filesystem. */ diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c index 40ac36f2..055288a5 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c @@ -25,12 +25,14 @@ #include "rdp.h" #include "rdp_print_job.h" #include "rdp_status.h" +#include "unicode.h" #include #include #include #include #include +#include #include #ifdef ENABLE_WINPR @@ -141,18 +143,25 @@ static void guac_rdpdr_device_printer_announce_handler(guac_rdpdr_device* device Stream_Write(output_stream, "PRN1\0\0\0\0", 8); /* DOS name */ /* Printer data */ - Stream_Write_UINT32(output_stream, 24 + GUAC_PRINTER_DRIVER_LENGTH + GUAC_PRINTER_NAME_LENGTH); + 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, GUAC_PRINTER_NAME_LENGTH); /* PrinterName 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, GUAC_PRINTER_NAME, GUAC_PRINTER_NAME_LENGTH); + Stream_Write(output_stream, printer_name, printer_name_length); } @@ -190,7 +199,7 @@ static void guac_rdpdr_device_printer_free_handler(guac_rdpdr_device* device) { /* Do nothing */ } -void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr) { +void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name) { int id = rdpdr->devices_registered++; @@ -200,7 +209,7 @@ void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr) { /* Init device */ device->rdpdr = rdpdr; device->device_id = id; - device->device_name = "Guacamole Printer"; + device->device_name = printer_name; /* Set handlers */ device->announce_handler = guac_rdpdr_device_printer_announce_handler; diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.h b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.h index 6f203d6b..3d48dad9 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.h +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.h @@ -35,7 +35,7 @@ * Registers a new printer device within the RDPDR plugin. This must be done * before RDPDR connection finishes. */ -void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr); +void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name); #endif diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_service.c b/src/protocols/rdp/guac_rdpdr/rdpdr_service.c index 233b117c..611d21a5 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_service.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_service.c @@ -96,7 +96,7 @@ void guac_rdpdr_process_connect(rdpSvcPlugin* plugin) { /* Register printer if enabled */ if (rdp_client->settings->printing_enabled) - guac_rdpdr_register_printer(rdpdr); + guac_rdpdr_register_printer(rdpdr, rdp_client->settings->printer_name); /* Register drive if enabled */ if (rdp_client->settings->drive_enabled) diff --git a/src/protocols/rdp/rdp_settings.c b/src/protocols/rdp/rdp_settings.c index 0ce3e846..18525429 100644 --- a/src/protocols/rdp/rdp_settings.c +++ b/src/protocols/rdp/rdp_settings.c @@ -990,6 +990,7 @@ void guac_rdp_settings_free(guac_rdp_settings* settings) { free(settings->remote_app_args); free(settings->remote_app_dir); free(settings->username); + free(settings->printer_name); /* Free channel name array */ if (settings->svc_names != NULL) { From a1ec5d9ad732053f6fb729c5816bee8398197e34 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sat, 24 Mar 2018 16:22:55 -0400 Subject: [PATCH 3/3] 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,