GUACAMOLE-445: Merge support for defining the RDP printer name.

This commit is contained in:
Michael Jumper 2018-07-03 19:24:07 -07:00
commit da1e078242
9 changed files with 122 additions and 67 deletions

View File

@ -29,6 +29,7 @@
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/socket.h> #include <guacamole/socket.h>
#include <guacamole/unicode.h>
#ifdef ENABLE_WINPR #ifdef ENABLE_WINPR
#include <winpr/stream.h> #include <winpr/stream.h>
@ -36,21 +37,6 @@
#include "compat/winpr-stream.h" #include "compat/winpr-stream.h"
#endif #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, 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) { 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) { 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) { void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr) {
@ -143,9 +132,21 @@ void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr) {
device->rdpdr = rdpdr; device->rdpdr = rdpdr;
device->device_id = id; device->device_id = id;
device->device_name = "Guacamole Filesystem"; 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 */ /* Set handlers */
device->announce_handler = guac_rdpdr_device_fs_announce_handler;
device->iorequest_handler = guac_rdpdr_device_fs_iorequest_handler; device->iorequest_handler = guac_rdpdr_device_fs_iorequest_handler;
device->free_handler = guac_rdpdr_device_fs_free_handler; device->free_handler = guac_rdpdr_device_fs_free_handler;

View File

@ -22,9 +22,11 @@
#include "rdp.h" #include "rdp.h"
#include "rdpdr_messages.h" #include "rdpdr_messages.h"
#include "rdpdr_service.h" #include "rdpdr_service.h"
#include "unicode.h"
#include <freerdp/utils/svc_plugin.h> #include <freerdp/utils/svc_plugin.h>
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/unicode.h>
#ifdef ENABLE_WINPR #ifdef ENABLE_WINPR
#include <winpr/stream.h> #include <winpr/stream.h>
@ -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) { static void guac_rdpdr_send_client_device_list_announce_request(guac_rdpdrPlugin* rdpdr) {
int i; /* Calculate number of bytes needed for the stream */
wStream* output_stream = Stream_New(NULL, 256); 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 */ /* Write header */
Stream_Write_UINT16(output_stream, RDPDR_CTYP_CORE); Stream_Write_UINT16(output_stream, RDPDR_CTYP_CORE);
Stream_Write_UINT16(output_stream, PAKID_CORE_DEVICELIST_ANNOUNCE); 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); Stream_Write_UINT32(output_stream, rdpdr->devices_registered);
for (i=0; i<rdpdr->devices_registered; i++) { for (int i=0; i<rdpdr->devices_registered; i++) {
guac_rdpdr_device* device = &(rdpdr->devices[i]);
device->announce_handler(device, output_stream, 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)", 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); svc_plugin_send((rdpSvcPlugin*) rdpdr, output_stream);
@ -273,4 +284,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) { 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"); guac_client_log(rdpdr->client, GUAC_LOG_INFO, "Printer unexpectedly switched to XPS mode");
} }

View File

@ -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 "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 #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. * Name of the filesystem.
*/ */

View File

@ -25,12 +25,14 @@
#include "rdp.h" #include "rdp.h"
#include "rdp_print_job.h" #include "rdp_print_job.h"
#include "rdp_status.h" #include "rdp_status.h"
#include "unicode.h"
#include <freerdp/utils/svc_plugin.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>
#include <guacamole/stream.h> #include <guacamole/stream.h>
#include <guacamole/unicode.h>
#include <guacamole/user.h> #include <guacamole/user.h>
#ifdef ENABLE_WINPR #ifdef ENABLE_WINPR
@ -131,31 +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 */
Stream_Write_UINT32(output_stream, 24 + GUAC_PRINTER_DRIVER_LENGTH + GUAC_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, 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);
}
static void guac_rdpdr_device_printer_iorequest_handler(guac_rdpdr_device* device, 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) { wStream* input_stream, int file_id, int completion_id, int major_func, int minor_func) {
@ -187,10 +164,12 @@ static void guac_rdpdr_device_printer_iorequest_handler(guac_rdpdr_device* devic
} }
static void guac_rdpdr_device_printer_free_handler(guac_rdpdr_device* device) { 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) { void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name) {
int id = rdpdr->devices_registered++; int id = rdpdr->devices_registered++;
@ -200,10 +179,42 @@ void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr) {
/* Init device */ /* Init device */
device->rdpdr = rdpdr; device->rdpdr = rdpdr;
device->device_id = id; device->device_id = id;
device->device_name = "Guacamole Printer"; 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 */ /* Set handlers */
device->announce_handler = guac_rdpdr_device_printer_announce_handler;
device->iorequest_handler = guac_rdpdr_device_printer_iorequest_handler; device->iorequest_handler = guac_rdpdr_device_printer_iorequest_handler;
device->free_handler = guac_rdpdr_device_printer_free_handler; device->free_handler = guac_rdpdr_device_printer_free_handler;

View File

@ -34,8 +34,15 @@
/** /**
* Registers a new printer device within the RDPDR plugin. This must be done * Registers a new printer device within the RDPDR plugin. This must be done
* before RDPDR connection finishes. * 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); void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name);
#endif #endif

View File

@ -96,7 +96,7 @@ void guac_rdpdr_process_connect(rdpSvcPlugin* plugin) {
/* Register printer if enabled */ /* Register printer if enabled */
if (rdp_client->settings->printing_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 */ /* Register drive if enabled */
if (rdp_client->settings->drive_enabled) if (rdp_client->settings->drive_enabled)

View File

@ -74,15 +74,30 @@ struct guac_rdpdr_device {
int device_id; 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; const char* device_name;
/** /**
* Handler which will be called when the RDPDR plugin is forming the client * The type of RDPDR device that this represents.
* device announce list.
*/ */
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. * 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; 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; 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); 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. * used for virtually all responses.
*/ */
wStream* guac_rdpdr_new_io_completion(guac_rdpdr_device* device, wStream* guac_rdpdr_new_io_completion(guac_rdpdr_device* device,

View File

@ -52,6 +52,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
"color-depth", "color-depth",
"disable-audio", "disable-audio",
"enable-printing", "enable-printing",
"printer-name",
"enable-drive", "enable-drive",
"drive-path", "drive-path",
"create-drive-path", "create-drive-path",
@ -187,6 +188,11 @@ enum RDP_ARGS_IDX {
*/ */
IDX_ENABLE_PRINTING, 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 * "true" if the virtual drive should be enabled, "false" or blank
* otherwise. * otherwise.
@ -794,6 +800,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
IDX_ENABLE_PRINTING, 0); 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 */ /* Drive enable/disable */
settings->drive_enabled = settings->drive_enabled =
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
@ -990,6 +1001,7 @@ void guac_rdp_settings_free(guac_rdp_settings* settings) {
free(settings->remote_app_args); free(settings->remote_app_args);
free(settings->remote_app_dir); free(settings->remote_app_dir);
free(settings->username); free(settings->username);
free(settings->printer_name);
/* Free channel name array */ /* Free channel name array */
if (settings->svc_names != NULL) { if (settings->svc_names != NULL) {

View File

@ -177,6 +177,11 @@ typedef struct guac_rdp_settings {
*/ */
int printing_enabled; int printing_enabled;
/**
* Name of the redirected printer.
*/
char* printer_name;
/** /**
* Whether the virtual drive is enabled. * Whether the virtual drive is enabled.
*/ */