From d2083a1aed38008cb8d01e465bb035449f0547ca Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 29 Dec 2019 18:04:27 -0800 Subject: [PATCH] GUACAMOLE-249: Refactor RDPDR to be more documentable. Document RDPDR fully. --- .../rdpdr/rdpdr-fs-messages-dir-info.c | 53 ++--- .../rdpdr/rdpdr-fs-messages-dir-info.h | 44 +++-- .../rdpdr/rdpdr-fs-messages-file-info.c | 124 ++++++------ .../rdpdr/rdpdr-fs-messages-file-info.h | 64 ++++--- .../rdpdr/rdpdr-fs-messages-vol-info.c | 57 +++--- .../rdpdr/rdpdr-fs-messages-vol-info.h | 20 +- .../rdp/channels/rdpdr/rdpdr-fs-messages.c | 181 ++++++++---------- .../rdp/channels/rdpdr/rdpdr-fs-messages.h | 49 ++--- src/protocols/rdp/channels/rdpdr/rdpdr-fs.c | 54 +++--- src/protocols/rdp/channels/rdpdr/rdpdr-fs.h | 10 + .../rdp/channels/rdpdr/rdpdr-messages.c | 81 ++++++-- .../rdp/channels/rdpdr/rdpdr-messages.h | 105 ++++++++-- .../rdp/channels/rdpdr/rdpdr-printer.c | 40 ++-- .../rdp/channels/rdpdr/rdpdr-printer.h | 39 ++++ src/protocols/rdp/channels/rdpdr/rdpdr.h | 97 +++++++++- 15 files changed, 625 insertions(+), 393 deletions(-) diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-dir-info.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-dir-info.c index 256ac14a..25d355f5 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-dir-info.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-dir-info.c @@ -18,6 +18,7 @@ */ #include "config.h" +#include "channels/rdpdr/rdpdr-fs-messages-dir-info.h" #include "channels/rdpdr/rdpdr.h" #include "fs.h" #include "unicode.h" @@ -29,8 +30,8 @@ #include void guac_rdpdr_fs_process_query_directory_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, const char* entry_name, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + const char* entry_name, int entry_file_id) { guac_rdp_fs_file* file; @@ -43,16 +44,17 @@ void guac_rdpdr_fs_process_query_directory_info(guac_rdp_common_svc* svc, (char*) utf16_entry_name, sizeof(utf16_entry_name)); /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, entry_file_id); if (file == NULL) return; guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i (entry_name=\"%s\")]", - __func__, file_id, entry_name); + __func__, entry_file_id, entry_name); - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 4 + 64 + utf16_length + 2); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, + 4 + 64 + utf16_length + 2); Stream_Write_UINT32(output_stream, 64 + utf16_length + 2); /* Length */ @@ -76,8 +78,8 @@ void guac_rdpdr_fs_process_query_directory_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_query_full_directory_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, const char* entry_name, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + const char* entry_name, int entry_file_id) { guac_rdp_fs_file* file; @@ -90,16 +92,17 @@ void guac_rdpdr_fs_process_query_full_directory_info(guac_rdp_common_svc* svc, (char*) utf16_entry_name, sizeof(utf16_entry_name)); /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, entry_file_id); if (file == NULL) return; guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i (entry_name=\"%s\")]", - __func__, file_id, entry_name); + __func__, entry_file_id, entry_name); - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 4 + 68 + utf16_length + 2); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, + 4 + 68 + utf16_length + 2); Stream_Write_UINT32(output_stream, 68 + utf16_length + 2); /* Length */ @@ -124,8 +127,8 @@ void guac_rdpdr_fs_process_query_full_directory_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_query_both_directory_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, const char* entry_name, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + const char* entry_name, int entry_file_id) { guac_rdp_fs_file* file; @@ -138,16 +141,17 @@ void guac_rdpdr_fs_process_query_both_directory_info(guac_rdp_common_svc* svc, (char*) utf16_entry_name, sizeof(utf16_entry_name)); /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, entry_file_id); if (file == NULL) return; guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i (entry_name=\"%s\")]", - __func__, file_id, entry_name); + __func__, entry_file_id, entry_name); - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 4 + 69 + 24 + utf16_length + 2); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, + 4 + 69 + 24 + utf16_length + 2); Stream_Write_UINT32(output_stream, 69 + 24 + utf16_length + 2); /* Length */ @@ -176,8 +180,8 @@ void guac_rdpdr_fs_process_query_both_directory_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_query_names_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, const char* entry_name, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + const char* entry_name, int entry_file_id) { guac_rdp_fs_file* file; @@ -190,16 +194,17 @@ void guac_rdpdr_fs_process_query_names_info(guac_rdp_common_svc* svc, (char*) utf16_entry_name, sizeof(utf16_entry_name)); /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, entry_file_id); if (file == NULL) return; guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i (entry_name=\"%s\")]", - __func__, file_id, entry_name); + __func__, entry_file_id, entry_name); - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 4 + 12 + utf16_length + 2); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, + 4 + 12 + utf16_length + 2); Stream_Write_UINT32(output_stream, 12 + utf16_length + 2); /* Length */ diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-dir-info.h b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-dir-info.h index 8bb4ac68..c4b0f8ad 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-dir-info.h +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-dir-info.h @@ -34,40 +34,60 @@ #include +/** + * Handler for Device I/O Requests which query information about the files + * within a directory. + * + * @param svc + * The guac_rdp_common_svc representing the static virtual channel being + * used for RDPDR. + * + * @param device + * The guac_rdpdr_device of the relevant device, as dictated by the + * deviceId field of common RDPDR header within the received PDU. Within + * the guac_rdpdr_iorequest structure, the deviceId field is stored within + * device_id. + * + * @param iorequest + * The contents of the common RDPDR Device I/O Request header shared by all + * RDPDR devices. + * + * @param entry_name + * The filename of the file being queried. + * + * @param entry_file_id + * The ID of the file being queried. + */ +typedef void guac_rdpdr_directory_query_handler(guac_rdp_common_svc* svc, + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + const char* entry_name, int entry_file_id); + /** * Processes a query request for FileDirectoryInformation. From the * documentation this is "defined as the file's name, time stamp, and size, or its * attributes." */ -void guac_rdpdr_fs_process_query_directory_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, const char* entry_name, int file_id, - int completion_id); +guac_rdpdr_directory_query_handler guac_rdpdr_fs_process_query_directory_info; /** * Processes a query request for FileFullDirectoryInformation. From the * documentation, this is "defined as all the basic information, plus extended * attribute size." */ -void guac_rdpdr_fs_process_query_full_directory_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, const char* entry_name, int file_id, - int completion_id); +guac_rdpdr_directory_query_handler guac_rdpdr_fs_process_query_full_directory_info; /** * Processes a query request for FileBothDirectoryInformation. From the * documentation, this absurdly-named request is "basic information plus * extended attribute size and short name about a file or directory." */ -void guac_rdpdr_fs_process_query_both_directory_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, const char* entry_name, int file_id, - int completion_id); +guac_rdpdr_directory_query_handler guac_rdpdr_fs_process_query_both_directory_info; /** * Processes a query request for FileNamesInformation. From the documentation, * this is "detailed information on the names of files in a directory." */ -void guac_rdpdr_fs_process_query_names_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, const char* entry_name, int file_id, - int completion_id); +guac_rdpdr_directory_query_handler guac_rdpdr_fs_process_query_names_info; #endif diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c index 4629ca59..509087b8 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c @@ -18,6 +18,7 @@ */ #include "config.h" +#include "channels/rdpdr/rdpdr-fs-messages-file-info.h" #include "channels/rdpdr/rdpdr.h" #include "fs.h" #include "unicode.h" @@ -31,23 +32,22 @@ #include void guac_rdpdr_fs_process_query_basic_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream; guac_rdp_fs_file* file; /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, iorequest->file_id); if (file == NULL) return; - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, + iorequest->file_id); - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 40); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, 40); Stream_Write_UINT32(output_stream, 36); Stream_Write_UINT64(output_stream, file->ctime); /* CreationTime */ @@ -63,27 +63,26 @@ void guac_rdpdr_fs_process_query_basic_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_query_standard_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream; guac_rdp_fs_file* file; BOOL is_directory = FALSE; /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, iorequest->file_id); if (file == NULL) return; - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, + iorequest->file_id); if (file->attributes & FILE_ATTRIBUTE_DIRECTORY) is_directory = TRUE; - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 26); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, 26); Stream_Write_UINT32(output_stream, 22); Stream_Write_UINT64(output_stream, file->size); /* AllocationSize */ @@ -99,23 +98,22 @@ void guac_rdpdr_fs_process_query_standard_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_query_attribute_tag_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream; guac_rdp_fs_file* file; /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, iorequest->file_id); if (file == NULL) return; - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, + iorequest->file_id); - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 12); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, 12); Stream_Write_UINT32(output_stream, 8); Stream_Write_UINT32(output_stream, file->attributes); /* FileAttributes */ @@ -128,8 +126,8 @@ void guac_rdpdr_fs_process_query_attribute_tag_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_set_rename_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + int length, wStream* input_stream) { int result; int filename_length; @@ -145,9 +143,9 @@ void guac_rdpdr_fs_process_set_rename_info(guac_rdp_common_svc* svc, guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), filename_length/2, destination_path, sizeof(destination_path)); - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i] destination_path=\"%s\"", - __func__, file_id, destination_path); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]" + "destination_path=\"%s\"", __func__, iorequest->file_id, + destination_path); /* If file moving to \Download folder, start stream, do not move */ if (strncmp(destination_path, "\\Download\\", 10) == 0) { @@ -155,28 +153,28 @@ void guac_rdpdr_fs_process_set_rename_info(guac_rdp_common_svc* svc, guac_rdp_fs_file* file; /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, iorequest->file_id); if (file == NULL) return; /* Initiate download, pretend move succeeded */ guac_rdpdr_start_download(svc, device, file->absolute_path); output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 4); + iorequest->completion_id, STATUS_SUCCESS, 4); } /* Otherwise, rename as requested */ else { - result = guac_rdp_fs_rename((guac_rdp_fs*) device->data, file_id, - destination_path); + result = guac_rdp_fs_rename((guac_rdp_fs*) device->data, + iorequest->file_id, destination_path); if (result < 0) output_stream = guac_rdpdr_new_io_completion(device, - completion_id, guac_rdp_fs_get_status(result), 4); + iorequest->completion_id, guac_rdp_fs_get_status(result), 4); else output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 4); + iorequest->completion_id, STATUS_SUCCESS, 4); } @@ -186,8 +184,8 @@ void guac_rdpdr_fs_process_set_rename_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_set_allocation_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + int length, wStream* input_stream) { int result; UINT64 size; @@ -196,18 +194,17 @@ void guac_rdpdr_fs_process_set_allocation_info(guac_rdp_common_svc* svc, /* Read new size */ Stream_Read_UINT64(input_stream, size); /* AllocationSize */ - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i] size=%" PRIu64, - __func__, file_id, (uint64_t) size); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] " + "size=%" PRIu64, __func__, iorequest->file_id, (uint64_t) size); /* Truncate file */ - result = guac_rdp_fs_truncate((guac_rdp_fs*) device->data, file_id, size); + result = guac_rdp_fs_truncate((guac_rdp_fs*) device->data, iorequest->file_id, size); if (result < 0) output_stream = guac_rdpdr_new_io_completion(device, - completion_id, guac_rdp_fs_get_status(result), 4); + iorequest->completion_id, guac_rdp_fs_get_status(result), 4); else output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 4); + iorequest->completion_id, STATUS_SUCCESS, 4); Stream_Write_UINT32(output_stream, length); guac_rdp_common_svc_write(svc, output_stream); @@ -215,23 +212,22 @@ void guac_rdpdr_fs_process_set_allocation_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_set_disposition_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + int length, wStream* input_stream) { wStream* output_stream; /* Delete file */ - int result = guac_rdp_fs_delete((guac_rdp_fs*) device->data, file_id); + int result = guac_rdp_fs_delete((guac_rdp_fs*) device->data, iorequest->file_id); if (result < 0) output_stream = guac_rdpdr_new_io_completion(device, - completion_id, guac_rdp_fs_get_status(result), 4); + iorequest->completion_id, guac_rdp_fs_get_status(result), 4); else output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 4); + iorequest->completion_id, STATUS_SUCCESS, 4); - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, + iorequest->file_id); Stream_Write_UINT32(output_stream, length); @@ -240,8 +236,8 @@ void guac_rdpdr_fs_process_set_disposition_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_set_end_of_file_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + int length, wStream* input_stream) { int result; UINT64 size; @@ -250,18 +246,17 @@ void guac_rdpdr_fs_process_set_end_of_file_info(guac_rdp_common_svc* svc, /* Read new size */ Stream_Read_UINT64(input_stream, size); /* AllocationSize */ - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i] size=%" PRIu64, - __func__, file_id, (uint64_t) size); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] " + "size=%" PRIu64, __func__, iorequest->file_id, (uint64_t) size); /* Truncate file */ - result = guac_rdp_fs_truncate((guac_rdp_fs*) device->data, file_id, size); + result = guac_rdp_fs_truncate((guac_rdp_fs*) device->data, iorequest->file_id, size); if (result < 0) output_stream = guac_rdpdr_new_io_completion(device, - completion_id, guac_rdp_fs_get_status(result), 4); + iorequest->completion_id, guac_rdp_fs_get_status(result), 4); else output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 4); + iorequest->completion_id, STATUS_SUCCESS, 4); Stream_Write_UINT32(output_stream, length); guac_rdp_common_svc_write(svc, output_stream); @@ -269,18 +264,17 @@ void guac_rdpdr_fs_process_set_end_of_file_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_set_basic_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + int length, wStream* input_stream) { wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 4); + iorequest->completion_id, STATUS_SUCCESS, 4); /* Currently do nothing, just respond */ Stream_Write_UINT32(output_stream, length); - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i] IGNORED", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] IGNORED", + __func__, iorequest->file_id); guac_rdp_common_svc_write(svc, output_stream); diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.h b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.h index d2198f5d..dfd207ae 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.h +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.h @@ -33,72 +33,88 @@ #include +/** + * Handler for Device I/O Requests which set/update file information. + * + * @param svc + * The guac_rdp_common_svc representing the static virtual channel being + * used for RDPDR. + * + * @param device + * The guac_rdpdr_device of the relevant device, as dictated by the + * deviceId field of common RDPDR header within the received PDU. Within + * the guac_rdpdr_iorequest structure, the deviceId field is stored within + * device_id. + * + * @param iorequest + * The contents of the common RDPDR Device I/O Request header shared by all + * RDPDR devices. + * + * @param length + * The length of the SetBuffer field of the I/O request, in bytes. Whether + * the SetBuffer field is applicable to a particular request, as well as + * the specific contents of that field, depend on the type of request. + * + * @param input_stream + * The remaining data within the received PDU, following the common RDPDR + * Device I/O Request header and length field. If the SetBuffer field is + * used for this request, the first byte of SetBuffer will be the first + * byte read from this stream. + */ +typedef void guac_rdpdr_set_information_request_handler(guac_rdp_common_svc* svc, + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + int length, wStream* input_stream); + /** * Processes a query for FileBasicInformation. From the documentation, this is * "used to query a file for the times of creation, last access, last write, * and change, in addition to file attribute information." */ -void guac_rdpdr_fs_process_query_basic_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_basic_info; /** * Processes a query for FileStandardInformation. From the documentation, this * is "used to query for file information such as allocation size, end-of-file * position, and number of links." */ -void guac_rdpdr_fs_process_query_standard_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_standard_info; /** * Processes a query for FileAttributeTagInformation. From the documentation * this is "used to query for file attribute and reparse tag information." */ -void guac_rdpdr_fs_process_query_attribute_tag_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_attribute_tag_info; /** * Process a set operation for FileRenameInformation. From the documentation, * this operation is used to rename a file. */ -void guac_rdpdr_fs_process_set_rename_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length); +guac_rdpdr_set_information_request_handler guac_rdpdr_fs_process_set_rename_info; /** * Process a set operation for FileAllocationInformation. From the * documentation, this operation is used to set a file's allocation size. */ -void guac_rdpdr_fs_process_set_allocation_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length); +guac_rdpdr_set_information_request_handler guac_rdpdr_fs_process_set_allocation_info; /** * Process a set operation for FileDispositionInformation. From the * documentation, this operation is used to mark a file for deletion. */ -void guac_rdpdr_fs_process_set_disposition_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length); +guac_rdpdr_set_information_request_handler guac_rdpdr_fs_process_set_disposition_info; /** * Process a set operation for FileEndOfFileInformation. From the * documentation, this operation is used "to set end-of-file information for * a file." */ -void guac_rdpdr_fs_process_set_end_of_file_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length); +guac_rdpdr_set_information_request_handler guac_rdpdr_fs_process_set_end_of_file_info; /** * Process a set operation for FileBasicInformation. From the documentation, * this is "used to set file information such as the times of creation, last * access, last write, and change, in addition to file attributes." */ -void guac_rdpdr_fs_process_set_basic_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int length); +guac_rdpdr_set_information_request_handler guac_rdpdr_fs_process_set_basic_info; #endif diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-vol-info.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-vol-info.c index 77f4cce8..1ab9dd21 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-vol-info.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-vol-info.c @@ -19,6 +19,8 @@ #include "config.h" #include "channels/rdpdr/rdpdr-messages.h" +#include "channels/rdpdr/rdpdr-fs-messages-vol-info.h" +#include "channels/rdpdr/rdpdr-fs.h" #include "channels/rdpdr/rdpdr.h" #include "fs.h" @@ -28,15 +30,14 @@ #include void guac_rdpdr_fs_process_query_volume_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 21 + GUAC_FILESYSTEM_LABEL_LENGTH); + iorequest->completion_id, STATUS_SUCCESS, 21 + GUAC_FILESYSTEM_LABEL_LENGTH); - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, + iorequest->file_id); Stream_Write_UINT32(output_stream, 17 + GUAC_FILESYSTEM_LABEL_LENGTH); Stream_Write_UINT64(output_stream, 0); /* VolumeCreationTime */ @@ -51,18 +52,17 @@ void guac_rdpdr_fs_process_query_volume_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_query_size_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { guac_rdp_fs_info info = {0}; guac_rdp_fs_get_info((guac_rdp_fs*) device->data, &info); wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 28); + iorequest->completion_id, STATUS_SUCCESS, 28); - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, + iorequest->file_id); Stream_Write_UINT32(output_stream, 24); Stream_Write_UINT64(output_stream, info.blocks_total); /* TotalAllocationUnits */ @@ -75,15 +75,14 @@ void guac_rdpdr_fs_process_query_size_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_query_device_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 12); + iorequest->completion_id, STATUS_SUCCESS, 12); - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, + iorequest->file_id); Stream_Write_UINT32(output_stream, 8); Stream_Write_UINT32(output_stream, FILE_DEVICE_DISK); /* DeviceType */ @@ -94,17 +93,16 @@ void guac_rdpdr_fs_process_query_device_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_query_attribute_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { int name_len = guac_utf8_strlen(device->device_name); wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 16 + name_len); + iorequest->completion_id, STATUS_SUCCESS, 16 + name_len); - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, + iorequest->file_id); Stream_Write_UINT32(output_stream, 12 + name_len); Stream_Write_UINT32(output_stream, @@ -120,18 +118,17 @@ void guac_rdpdr_fs_process_query_attribute_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_query_full_size_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { guac_rdp_fs_info info = {0}; guac_rdp_fs_get_info((guac_rdp_fs*) device->data, &info); wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 36); + iorequest->completion_id, STATUS_SUCCESS, 36); - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, + iorequest->file_id); Stream_Write_UINT32(output_stream, 32); Stream_Write_UINT64(output_stream, info.blocks_total); /* TotalAllocationUnits */ diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-vol-info.h b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-vol-info.h index 9f0d10aa..87c0745c 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-vol-info.h +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-vol-info.h @@ -38,37 +38,27 @@ * documentation, this is "used to query information for a volume on which a * file system is mounted." */ -void guac_rdpdr_fs_process_query_volume_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_volume_info; /** * Processes a query request for FileFsSizeInformation. */ -void guac_rdpdr_fs_process_query_size_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_size_info; /** * Processes a query request for FileFsAttributeInformation. */ -void guac_rdpdr_fs_process_query_attribute_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_attribute_info; /** * Processes a query request for FileFsFullSizeInformation. */ -void guac_rdpdr_fs_process_query_full_size_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_full_size_info; /** * Processes a query request for FileFsDeviceInformation. */ -void guac_rdpdr_fs_process_query_device_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_device_info; #endif diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c index c8113d1a..4fede57a 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c @@ -39,7 +39,8 @@ #include void guac_rdpdr_fs_process_create(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream; int file_id; @@ -79,8 +80,8 @@ void guac_rdpdr_fs_process_create(guac_rdp_common_svc* svc, guac_client_log(svc->client, GUAC_LOG_ERROR, "File open refused (%i): \"%s\"", file_id, path); - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - guac_rdp_fs_get_status(file_id), 5); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, guac_rdp_fs_get_status(file_id), 5); Stream_Write_UINT32(output_stream, 0); /* fileId */ Stream_Write_UINT8(output_stream, 0); /* information */ } @@ -90,8 +91,8 @@ void guac_rdpdr_fs_process_create(guac_rdp_common_svc* svc, guac_rdp_fs_file* file; - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 5); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, 5); Stream_Write_UINT32(output_stream, file_id); /* fileId */ Stream_Write_UINT8(output_stream, 0); /* information */ @@ -113,8 +114,8 @@ void guac_rdpdr_fs_process_create(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_read(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { UINT32 length; UINT64 offset; @@ -129,7 +130,7 @@ void guac_rdpdr_fs_process_read(guac_rdp_common_svc* svc, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] length=%i, offset=%" PRIu64, - __func__, file_id, length, (uint64_t) offset); + __func__, iorequest->file_id, length, (uint64_t) offset); /* Ensure buffer size does not exceed a safe maximum */ if (length > GUAC_RDP_MAX_READ_BUFFER) @@ -139,20 +140,20 @@ void guac_rdpdr_fs_process_read(guac_rdp_common_svc* svc, buffer = malloc(length); /* Attempt read */ - bytes_read = guac_rdp_fs_read((guac_rdp_fs*) device->data, file_id, offset, - buffer, length); + bytes_read = guac_rdp_fs_read((guac_rdp_fs*) device->data, + iorequest->file_id, offset, buffer, length); /* If error, return invalid parameter */ if (bytes_read < 0) { - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - guac_rdp_fs_get_status(bytes_read), 4); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, guac_rdp_fs_get_status(bytes_read), 4); Stream_Write_UINT32(output_stream, 0); /* Length */ } /* Otherwise, send bytes read */ else { - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 4+bytes_read); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, 4+bytes_read); Stream_Write_UINT32(output_stream, bytes_read); /* Length */ Stream_Write(output_stream, buffer, bytes_read); /* ReadData */ } @@ -163,8 +164,8 @@ void guac_rdpdr_fs_process_read(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_write(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { UINT32 length; UINT64 offset; @@ -179,24 +180,24 @@ void guac_rdpdr_fs_process_write(guac_rdp_common_svc* svc, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] length=%i, offset=%" PRIu64, - __func__, file_id, length, (uint64_t) offset); + __func__, iorequest->file_id, length, (uint64_t) offset); /* Attempt write */ - bytes_written = guac_rdp_fs_write((guac_rdp_fs*) device->data, file_id, - offset, Stream_Pointer(input_stream), length); + bytes_written = guac_rdp_fs_write((guac_rdp_fs*) device->data, + iorequest->file_id, offset, Stream_Pointer(input_stream), length); /* If error, return invalid parameter */ if (bytes_written < 0) { - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - guac_rdp_fs_get_status(bytes_written), 5); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, guac_rdp_fs_get_status(bytes_written), 5); Stream_Write_UINT32(output_stream, 0); /* Length */ Stream_Write_UINT8(output_stream, 0); /* Padding */ } /* Otherwise, send success */ else { - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 5); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, 5); Stream_Write_UINT32(output_stream, bytes_written); /* Length */ Stream_Write_UINT8(output_stream, 0); /* Padding */ } @@ -206,18 +207,17 @@ void guac_rdpdr_fs_process_write(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_close(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream; guac_rdp_fs_file* file; - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i]", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", + __func__, iorequest->file_id); /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, iorequest->file_id); if (file == NULL) return; @@ -225,14 +225,14 @@ void guac_rdpdr_fs_process_close(guac_rdp_common_svc* svc, if (file->bytes_written > 0 && strncmp(file->absolute_path, "\\Download\\", 10) == 0) { guac_rdpdr_start_download(svc, device, file->absolute_path); - guac_rdp_fs_delete((guac_rdp_fs*) device->data, file_id); + guac_rdp_fs_delete((guac_rdp_fs*) device->data, iorequest->file_id); } /* Close file */ - guac_rdp_fs_close((guac_rdp_fs*) device->data, file_id); + guac_rdp_fs_close((guac_rdp_fs*) device->data, iorequest->file_id); - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_SUCCESS, 4); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_SUCCESS, 4); Stream_Write(output_stream, "\0\0\0\0", 4); /* Padding */ guac_rdp_common_svc_write(svc, output_stream); @@ -240,8 +240,8 @@ void guac_rdpdr_fs_process_close(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_volume_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { int fs_information_class; @@ -251,28 +251,23 @@ void guac_rdpdr_fs_process_volume_info(guac_rdp_common_svc* svc, switch (fs_information_class) { case FileFsVolumeInformation: - guac_rdpdr_fs_process_query_volume_info(svc, device, input_stream, - file_id, completion_id); + guac_rdpdr_fs_process_query_volume_info(svc, device, iorequest, input_stream); break; case FileFsSizeInformation: - guac_rdpdr_fs_process_query_size_info(svc, device, input_stream, - file_id, completion_id); + guac_rdpdr_fs_process_query_size_info(svc, device, iorequest, input_stream); break; case FileFsDeviceInformation: - guac_rdpdr_fs_process_query_device_info(svc, device, input_stream, - file_id, completion_id); + guac_rdpdr_fs_process_query_device_info(svc, device, iorequest, input_stream); break; case FileFsAttributeInformation: - guac_rdpdr_fs_process_query_attribute_info(svc, device, - input_stream, file_id, completion_id); + guac_rdpdr_fs_process_query_attribute_info(svc, device, iorequest, input_stream); break; case FileFsFullSizeInformation: - guac_rdpdr_fs_process_query_full_size_info(svc, device, - input_stream, file_id, completion_id); + guac_rdpdr_fs_process_query_full_size_info(svc, device, iorequest, input_stream); break; default: @@ -283,8 +278,8 @@ void guac_rdpdr_fs_process_volume_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_file_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { int fs_information_class; @@ -294,18 +289,15 @@ void guac_rdpdr_fs_process_file_info(guac_rdp_common_svc* svc, switch (fs_information_class) { case FileBasicInformation: - guac_rdpdr_fs_process_query_basic_info(svc, device, input_stream, - file_id, completion_id); + guac_rdpdr_fs_process_query_basic_info(svc, device, iorequest, input_stream); break; case FileStandardInformation: - guac_rdpdr_fs_process_query_standard_info(svc, device, - input_stream, file_id, completion_id); + guac_rdpdr_fs_process_query_standard_info(svc, device, iorequest, input_stream); break; case FileAttributeTagInformation: - guac_rdpdr_fs_process_query_attribute_tag_info(svc, device, - input_stream, file_id, completion_id); + guac_rdpdr_fs_process_query_attribute_tag_info(svc, device, iorequest, input_stream); break; default: @@ -316,23 +308,23 @@ void guac_rdpdr_fs_process_file_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_set_volume_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_NOT_SUPPORTED, 0); + iorequest->completion_id, STATUS_NOT_SUPPORTED, 0); guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] Set volume info not supported", - __func__, file_id); + __func__, iorequest->file_id); guac_rdp_common_svc_write(svc, output_stream); } void guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { int fs_information_class; int length; @@ -345,28 +337,23 @@ void guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc* svc, switch (fs_information_class) { case FileBasicInformation: - guac_rdpdr_fs_process_set_basic_info(svc, device, input_stream, - file_id, completion_id, length); + guac_rdpdr_fs_process_set_basic_info(svc, device, iorequest, length, input_stream); break; case FileEndOfFileInformation: - guac_rdpdr_fs_process_set_end_of_file_info(svc, device, - input_stream, file_id, completion_id, length); + guac_rdpdr_fs_process_set_end_of_file_info(svc, device, iorequest, length, input_stream); break; case FileDispositionInformation: - guac_rdpdr_fs_process_set_disposition_info(svc, device, - input_stream, file_id, completion_id, length); + guac_rdpdr_fs_process_set_disposition_info(svc, device, iorequest, length, input_stream); break; case FileRenameInformation: - guac_rdpdr_fs_process_set_rename_info(svc, device, input_stream, - file_id, completion_id, length); + guac_rdpdr_fs_process_set_rename_info(svc, device, iorequest, length, input_stream); break; case FileAllocationInformation: - guac_rdpdr_fs_process_set_allocation_info(svc, device, - input_stream, file_id, completion_id, length); + guac_rdpdr_fs_process_set_allocation_info(svc, device, iorequest, length, input_stream); break; default: @@ -378,15 +365,14 @@ void guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_device_control(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_INVALID_PARAMETER, 4); + iorequest->completion_id, STATUS_INVALID_PARAMETER, 4); - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i] IGNORED", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] IGNORED", + __func__, iorequest->file_id); /* No content for now */ Stream_Write_UINT32(output_stream, 0); @@ -396,18 +382,17 @@ void guac_rdpdr_fs_process_device_control(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_notify_change_directory(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i] Not implemented", - __func__, file_id); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] Not " + "implemented", __func__, iorequest->file_id); } void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream; @@ -418,7 +403,7 @@ void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc, const char* entry_name; /* Get file */ - file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); + file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, iorequest->file_id); if (file == NULL) return; @@ -438,13 +423,13 @@ void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc, } - guac_client_log(svc->client, GUAC_LOG_DEBUG, - "%s: [file_id=%i] initial_query=%i, dir_pattern=\"%s\"", - __func__, file_id, initial_query, file->dir_pattern); + guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] " + "initial_query=%i, dir_pattern=\"%s\"", __func__, + iorequest->file_id, initial_query, file->dir_pattern); /* Find first matching entry in directory */ while ((entry_name = guac_rdp_fs_read_dir((guac_rdp_fs*) device->data, - file_id)) != NULL) { + iorequest->file_id)) != NULL) { /* Convert to absolute path */ char entry_path[GUAC_RDP_FS_MAX_PATH]; @@ -468,24 +453,22 @@ void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc, case FileDirectoryInformation: guac_rdpdr_fs_process_query_directory_info(svc, device, - entry_name, entry_file_id, completion_id); + iorequest, entry_name, entry_file_id); break; case FileFullDirectoryInformation: guac_rdpdr_fs_process_query_full_directory_info(svc, - device, entry_name, entry_file_id, - completion_id); + device, iorequest, entry_name, entry_file_id); break; case FileBothDirectoryInformation: guac_rdpdr_fs_process_query_both_directory_info(svc, - device, entry_name, entry_file_id, - completion_id); + device, iorequest, entry_name, entry_file_id); break; case FileNamesInformation: guac_rdpdr_fs_process_query_names_info(svc, device, - entry_name, entry_file_id, completion_id); + iorequest, entry_name, entry_file_id); break; default: @@ -505,8 +488,8 @@ void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc, * Handle errors as a lack of files. */ - output_stream = guac_rdpdr_new_io_completion(device, completion_id, - STATUS_NO_MORE_FILES, 5); + output_stream = guac_rdpdr_new_io_completion(device, + iorequest->completion_id, STATUS_NO_MORE_FILES, 5); Stream_Write_UINT32(output_stream, 0); /* Length */ Stream_Write_UINT8(output_stream, 0); /* Padding */ @@ -516,15 +499,15 @@ void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc, } void guac_rdpdr_fs_process_lock_control(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_NOT_SUPPORTED, 5); + iorequest->completion_id, STATUS_NOT_SUPPORTED, 5); guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] Lock not supported", - __func__, file_id); + __func__, iorequest->file_id); Stream_Zero(output_stream, 5); /* Padding */ diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.h b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.h index dd5454cc..bfc8312b 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.h +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.h @@ -37,37 +37,28 @@ * Handles a Server Create Drive Request. Despite its name, this request opens * a file. */ -void guac_rdpdr_fs_process_create(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_create; /** - * Handles a Server Close Drive Reqiest. This request closes an open file. + * Handles a Server Close Drive Request. This request closes an open file. */ -void guac_rdpdr_fs_process_close(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_close; /** * Handles a Server Drive Read Request. This request reads from a file. */ -void guac_rdpdr_fs_process_read(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_read; /** * Handles a Server Drive Write Request. This request writes to a file. */ -void guac_rdpdr_fs_process_write(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_write; /** * Handles a Server Drive Control Request. This request handles one of any * number of Windows FSCTL_* control functions. */ -void guac_rdpdr_fs_process_device_control(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_device_control; /** * Handles a Server Drive Query Volume Information Request. This request @@ -75,60 +66,46 @@ void guac_rdpdr_fs_process_device_control(guac_rdp_common_svc* svc, * has several query types which have their own handlers defined in a * separate file. */ -void guac_rdpdr_fs_process_volume_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_volume_info; /** * Handles a Server Drive Set Volume Information Request. Currently, this * RDPDR implementation does not support setting of volume information. */ -void guac_rdpdr_fs_process_set_volume_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_set_volume_info; /** * Handles a Server Drive Query Information Request. This request queries * information about a specific file. This request has several query types * which have their own handlers defined in a separate file. */ -void guac_rdpdr_fs_process_file_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_file_info; /** * Handles a Server Drive Set Information Request. This request sets * information about a specific file. Currently, this RDPDR implementation does * not support setting of file information. */ -void guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_set_file_info; /** * Handles a Server Drive Query Directory Request. This request queries * information about a specific directory. This request has several query types * which have their own handlers defined in a separate file. */ -void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_directory; /** * Handles a Server Drive NotifyChange Directory Request. This request requests * directory change notification. */ -void guac_rdpdr_fs_process_notify_change_directory(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_notify_change_directory; /** * Handles a Server Drive Lock Control Request. This request locks or unlocks * portions of a file. */ -void guac_rdpdr_fs_process_lock_control(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id); +guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_lock_control; #endif diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs.c index 3ca862cf..87e7d9fc 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs.c @@ -19,6 +19,7 @@ #include "config.h" #include "channels/rdpdr/rdpdr-fs-messages.h" +#include "channels/rdpdr/rdpdr-fs.h" #include "channels/rdpdr/rdpdr-messages.h" #include "channels/rdpdr/rdpdr.h" #include "rdp.h" @@ -30,96 +31,85 @@ #include #include -static void guac_rdpdr_device_fs_iorequest_handler(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int major_func, int minor_func) { +void guac_rdpdr_device_fs_iorequest_handler(guac_rdp_common_svc* svc, + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { - switch (major_func) { + switch (iorequest->major_func) { /* File open */ case IRP_MJ_CREATE: - guac_rdpdr_fs_process_create(svc, device, input_stream, - completion_id); + guac_rdpdr_fs_process_create(svc, device, iorequest, input_stream); break; /* File close */ case IRP_MJ_CLOSE: - guac_rdpdr_fs_process_close(svc, device, input_stream, file_id, - completion_id); + guac_rdpdr_fs_process_close(svc, device, iorequest, input_stream); break; /* File read */ case IRP_MJ_READ: - guac_rdpdr_fs_process_read(svc, device, input_stream, file_id, - completion_id); + guac_rdpdr_fs_process_read(svc, device, iorequest, input_stream); break; /* File write */ case IRP_MJ_WRITE: - guac_rdpdr_fs_process_write(svc, device, input_stream, file_id, - completion_id); + guac_rdpdr_fs_process_write(svc, device, iorequest, input_stream); break; /* Device control request (Windows FSCTL_ control codes) */ case IRP_MJ_DEVICE_CONTROL: - guac_rdpdr_fs_process_device_control(svc, device, input_stream, - file_id, completion_id); + guac_rdpdr_fs_process_device_control(svc, device, iorequest, input_stream); break; /* Query volume (drive) information */ case IRP_MJ_QUERY_VOLUME_INFORMATION: - guac_rdpdr_fs_process_volume_info(svc, device, input_stream, - file_id, completion_id); + guac_rdpdr_fs_process_volume_info(svc, device, iorequest, input_stream); break; /* Set volume (drive) information */ case IRP_MJ_SET_VOLUME_INFORMATION: - guac_rdpdr_fs_process_set_volume_info(svc, device, input_stream, - file_id, completion_id); + guac_rdpdr_fs_process_set_volume_info(svc, device, iorequest, input_stream); break; /* Query file information */ case IRP_MJ_QUERY_INFORMATION: - guac_rdpdr_fs_process_file_info(svc, device, input_stream, file_id, - completion_id); + guac_rdpdr_fs_process_file_info(svc, device, iorequest, input_stream); break; /* Set file information */ case IRP_MJ_SET_INFORMATION: - guac_rdpdr_fs_process_set_file_info(svc, device, input_stream, - file_id, completion_id); + guac_rdpdr_fs_process_set_file_info(svc, device, iorequest, input_stream); break; case IRP_MJ_DIRECTORY_CONTROL: /* Enumerate directory contents */ - if (minor_func == IRP_MN_QUERY_DIRECTORY) - guac_rdpdr_fs_process_query_directory(svc, device, - input_stream, file_id, completion_id); + if (iorequest->minor_func == IRP_MN_QUERY_DIRECTORY) + guac_rdpdr_fs_process_query_directory(svc, device, iorequest, + input_stream); /* Request notification of changes to directory */ - else if (minor_func == IRP_MN_NOTIFY_CHANGE_DIRECTORY) + else if (iorequest->minor_func == IRP_MN_NOTIFY_CHANGE_DIRECTORY) guac_rdpdr_fs_process_notify_change_directory(svc, device, - input_stream, - file_id, completion_id); + iorequest, input_stream); break; /* Lock/unlock portions of a file */ case IRP_MJ_LOCK_CONTROL: - guac_rdpdr_fs_process_lock_control(svc, device, input_stream, - file_id, completion_id); + guac_rdpdr_fs_process_lock_control(svc, device, iorequest, input_stream); break; default: guac_client_log(svc->client, GUAC_LOG_ERROR, "Unknown filesystem I/O request function: 0x%x/0x%x", - major_func, minor_func); + iorequest->major_func, iorequest->minor_func); } } -static void guac_rdpdr_device_fs_free_handler(guac_rdp_common_svc* svc, +void guac_rdpdr_device_fs_free_handler(guac_rdp_common_svc* svc, guac_rdpdr_device* device) { Stream_Free(device->device_announce, 1); diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs.h b/src/protocols/rdp/channels/rdpdr/rdpdr-fs.h index ab8a13db..6f6e5d1d 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs.h +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs.h @@ -36,6 +36,16 @@ #include +/** + * The UTF-16 string that should be sent as the label of the filesystem. + */ +#define GUAC_FILESYSTEM_LABEL "G\0U\0A\0C\0F\0I\0L\0E\0" + +/** + * The size of GUAC_FILESYSTEM_LABEL in bytes. + */ +#define GUAC_FILESYSTEM_LABEL_LENGTH 16 + /** * Registers a new filesystem device within the RDPDR plugin. This must be done * before RDPDR connection finishes. diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c b/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c index b9b67383..21bb3162 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c @@ -31,6 +31,28 @@ #include #include +/** + * Sends a Client Announce Reply message. The Client Announce Reply message is + * required to be sent in response to the Server Announce Request message. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/d6fe6d1b-c145-4a6f-99aa-4fe3cdcea398 + * + * @param svc + * The guac_rdp_common_svc representing the static virtual channel being + * used for RDPDR. + * + * @param major + * The major version of the RDPDR protocol in use. This value must always + * be 1. + * + * @param minor + * The minor version of the RDPDR protocol in use. This value must be + * either 2, 5, 10, 12, or 13. + * + * @param client_id + * The client ID received in the Server Announce Request, or a randomly + * generated ID. + */ static void guac_rdpdr_send_client_announce_reply(guac_rdp_common_svc* svc, unsigned int major, unsigned int minor, unsigned int client_id) { @@ -49,6 +71,19 @@ static void guac_rdpdr_send_client_announce_reply(guac_rdp_common_svc* svc, } +/** + * Sends a Client Name Request message. The Client Name Request message is used + * by the client to announce its own name. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/902497f1-3b1c-4aee-95f8-1668f9b7b7d2 + * + * @param svc + * The guac_rdp_common_svc representing the static virtual channel being + * used for RDPDR. + * + * @param name + * The name that should be used for the client. + */ static void guac_rdpdr_send_client_name_request(guac_rdp_common_svc* svc, const char* name) { @@ -69,6 +104,18 @@ static void guac_rdpdr_send_client_name_request(guac_rdp_common_svc* svc, } +/** + * Sends a Client Core Capability Response message. The Client Core Capability + * Response message is used to announce the client's capabilities, in response + * to receiving the server's capabilities via a Server Core Capability Request. + * See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/f513bf87-cca0-488a-ac5c-18cf18f4a7e1 + * + * @param svc + * The guac_rdp_common_svc representing the static virtual channel being + * used for RDPDR. + */ static void guac_rdpdr_send_client_capability(guac_rdp_common_svc* svc) { wStream* output_stream = Stream_New(NULL, 256); @@ -117,6 +164,17 @@ static void guac_rdpdr_send_client_capability(guac_rdp_common_svc* svc) { } +/** + * Sends a Client Device List Announce Request message. The Client Device List + * Announce Request message is used by the client to enumerate all devices + * which should be made available within the RDP session via RDPDR. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/10ef9ada-cba2-4384-ab60-7b6290ed4a9a + * + * @param svc + * The guac_rdp_common_svc representing the static virtual channel being + * used for RDPDR. + */ static void guac_rdpdr_send_client_device_list_announce_request(guac_rdp_common_svc* svc) { guac_rdpdr* rdpdr = (guac_rdpdr*) svc->data; @@ -220,28 +278,27 @@ void guac_rdpdr_process_device_iorequest(guac_rdp_common_svc* svc, wStream* input_stream) { guac_rdpdr* rdpdr = (guac_rdpdr*) svc->data; - - int device_id, file_id, completion_id, major_func, minor_func; + guac_rdpdr_iorequest iorequest; /* Read header */ - Stream_Read_UINT32(input_stream, device_id); - Stream_Read_UINT32(input_stream, file_id); - Stream_Read_UINT32(input_stream, completion_id); - Stream_Read_UINT32(input_stream, major_func); - Stream_Read_UINT32(input_stream, minor_func); + Stream_Read_UINT32(input_stream, iorequest.device_id); + Stream_Read_UINT32(input_stream, iorequest.file_id); + Stream_Read_UINT32(input_stream, iorequest.completion_id); + Stream_Read_UINT32(input_stream, iorequest.major_func); + Stream_Read_UINT32(input_stream, iorequest.minor_func); /* If printer, run printer handlers */ - if (device_id >= 0 && device_id < rdpdr->devices_registered) { + if (iorequest.device_id >= 0 && iorequest.device_id < rdpdr->devices_registered) { /* Call handler on device */ - guac_rdpdr_device* device = &(rdpdr->devices[device_id]); - device->iorequest_handler(svc, device, input_stream, - file_id, completion_id, major_func, minor_func); + guac_rdpdr_device* device = &(rdpdr->devices[iorequest.device_id]); + device->iorequest_handler(svc, device, &iorequest, input_stream); } else - guac_client_log(svc->client, GUAC_LOG_ERROR, "Unknown device ID: 0x%08x", device_id); + guac_client_log(svc->client, GUAC_LOG_ERROR, "Unknown device ID: " + "0x%08x", iorequest.device_id); } diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-messages.h b/src/protocols/rdp/channels/rdpdr/rdpdr-messages.h index d1352d72..27684cf2 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-messages.h +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-messages.h @@ -35,29 +35,102 @@ #define GUAC_OS_TYPE (*((uint32_t*) "GUAC")) /** - * Name of the printer driver that should be used on the server. + * Handler which processes a message specific to the RDPDR channel. + * + * @param svc + * The guac_rdp_common_svc representing the static virtual channel being + * used for RDPDR. + * + * @param input_stream + * A wStream containing the entire received message. */ -#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 +typedef void guac_rdpdr_message_handler(guac_rdp_common_svc* svc, + wStream* input_stream); /** - * Label of the filesystem. + * Handler which processes a received Server Announce Request message. The + * Server Announce Request message begins the RDPDR exchange and provides a + * client ID which the RDPDR client may use. The client may also supply its + * own, randomly-generated ID, and is required to do so for older versions of + * RDPDR. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/046047aa-62d8-49f9-bf16-7fe41880aaf4 */ -#define GUAC_FILESYSTEM_LABEL "G\0U\0A\0C\0F\0I\0L\0E\0" -#define GUAC_FILESYSTEM_LABEL_LENGTH 16 +guac_rdpdr_message_handler guac_rdpdr_process_server_announce; -/* - * Message handlers. +/** + * Handler which processes a received Server Client ID Confirm message. The + * Server Client ID Confirm message is sent by the server to confirm the client + * ID requested by the client (in its response to the Server Announce Request) + * has been accepted. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/bbbb9666-6994-4cf6-8e65-0d46eb319c6e */ +guac_rdpdr_message_handler guac_rdpdr_process_clientid_confirm; -void guac_rdpdr_process_server_announce(guac_rdp_common_svc* svc, wStream* input_stream); -void guac_rdpdr_process_clientid_confirm(guac_rdp_common_svc* svc, wStream* input_stream); -void guac_rdpdr_process_device_reply(guac_rdp_common_svc* svc, wStream* input_stream); -void guac_rdpdr_process_device_iorequest(guac_rdp_common_svc* svc, wStream* input_stream); -void guac_rdpdr_process_server_capability(guac_rdp_common_svc* svc, wStream* input_stream); -void guac_rdpdr_process_user_loggedon(guac_rdp_common_svc* svc, wStream* input_stream); -void guac_rdpdr_process_prn_cache_data(guac_rdp_common_svc* svc, wStream* input_stream); -void guac_rdpdr_process_prn_using_xps(guac_rdp_common_svc* svc, wStream* input_stream); +/** + * Handler which processes a received Server Device Announce Response message. + * The Server Device Announce Response message is sent in response to a Client + * Device List Announce message to communicate the success/failure status of + * device creation. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/a4c0b619-6e87-4721-bdc4-5d2db7f485f3 + */ +guac_rdpdr_message_handler guac_rdpdr_process_device_reply; + +/** + * Handler which processes a received Device I/O Request message. The Device + * I/O Request message makes up the majority of traffic once RDPDR is + * established. Each I/O request consists of a device-specific major/minor + * function number pair, as well as several parameters. Device-specific + * handling of I/O requests within Guacamole is delegated to device- and + * function-specific implementations of yet another function type: + * guac_rdpdr_device_iorequest_handler. + * + * See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/a087ffa8-d0d5-4874-ac7b-0494f63e2d5d + */ +guac_rdpdr_message_handler guac_rdpdr_process_device_iorequest; + +/** + * Handler which processes a received Server Core Capability Request message. + * The Server Core Capability Request message is sent by the server to + * communicate its capabilities and to request that the client communicate the + * same. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/702789c3-b924-4bc2-9280-3221bc7d6797 + */ +guac_rdpdr_message_handler guac_rdpdr_process_server_capability; + +/** + * Handler which processes a received Server User Logged On message. The Server + * User Logged On message is sent by the server to notify that the user has + * logged on to the session. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/dfc0e8ed-a242-4d00-bb88-e779e08f2f61 + */ +guac_rdpdr_message_handler guac_rdpdr_process_user_loggedon; + +/** + * Handler which processes any one of several RDPDR messages specific to cached + * printer configuration data, each of these messages having the same + * PAKID_PRN_CACHE_DATA packet ID. The Guacamole RDPDR implementation ignores + * all PAKID_PRN_CACHE_DATA messages. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpepc/7fccae60-f077-433b-9dee-9bad4238bf40 + */ +guac_rdpdr_message_handler guac_rdpdr_process_prn_cache_data; + +/** + * Handler which processes a received Server Printer Set XPS Mode message. The + * Server Printer Set XPS Mode message is specific to printers and requests + * that the client printer be set to XPS mode. The Guacamole RDPDR + * implementation ignores any request to set the printer to XPS mode. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpepc/f1789a66-bcd0-4df3-bfc2-6e7330d63145 + */ +guac_rdpdr_message_handler guac_rdpdr_process_prn_using_xps; #endif diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c b/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c index c3359631..e435d32b 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c @@ -43,7 +43,8 @@ #include void guac_rdpdr_process_print_job_create(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { guac_client* client = svc->client; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; @@ -57,7 +58,7 @@ void guac_rdpdr_process_print_job_create(guac_rdp_common_svc* svc, /* Respond with success */ wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 4); + iorequest->completion_id, STATUS_SUCCESS, 4); Stream_Write_UINT32(output_stream, 0); /* fileId */ guac_rdp_common_svc_write(svc, output_stream); @@ -65,7 +66,8 @@ void guac_rdpdr_process_print_job_create(guac_rdp_common_svc* svc, } void guac_rdpdr_process_print_job_write(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { guac_client* client = svc->client; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; @@ -94,7 +96,7 @@ void guac_rdpdr_process_print_job_write(guac_rdp_common_svc* svc, } wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, status, 5); + iorequest->completion_id, status, 5); Stream_Write_UINT32(output_stream, length); Stream_Write_UINT8(output_stream, 0); /* Padding */ @@ -104,7 +106,8 @@ void guac_rdpdr_process_print_job_write(guac_rdp_common_svc* svc, } void guac_rdpdr_process_print_job_close(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int completion_id) { + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { guac_client* client = svc->client; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; @@ -117,7 +120,7 @@ void guac_rdpdr_process_print_job_close(guac_rdp_common_svc* svc, } wStream* output_stream = guac_rdpdr_new_io_completion(device, - completion_id, STATUS_SUCCESS, 4); + iorequest->completion_id, STATUS_SUCCESS, 4); Stream_Write_UINT32(output_stream, 0); /* Padding */ guac_rdp_common_svc_write(svc, output_stream); @@ -127,41 +130,38 @@ void guac_rdpdr_process_print_job_close(guac_rdp_common_svc* svc, } -static void guac_rdpdr_device_printer_iorequest_handler(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int major_func, int minor_func) { +void guac_rdpdr_device_printer_iorequest_handler(guac_rdp_common_svc* svc, + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream) { - switch (major_func) { + switch (iorequest->major_func) { /* Print job create */ case IRP_MJ_CREATE: - guac_rdpdr_process_print_job_create(svc, device, input_stream, - completion_id); + guac_rdpdr_process_print_job_create(svc, device, iorequest, input_stream); break; /* Printer job write */ case IRP_MJ_WRITE: - guac_rdpdr_process_print_job_write(svc, device, input_stream, - completion_id); + guac_rdpdr_process_print_job_write(svc, device, iorequest, input_stream); break; /* Printer job close */ case IRP_MJ_CLOSE: - guac_rdpdr_process_print_job_close(svc, device, input_stream, - completion_id); + guac_rdpdr_process_print_job_close(svc, device, iorequest, input_stream); break; /* Log unknown */ default: - guac_client_log(svc->client, GUAC_LOG_ERROR, - "Unknown printer I/O request function: 0x%x/0x%x", - major_func, minor_func); + guac_client_log(svc->client, GUAC_LOG_ERROR, "Unknown printer " + "I/O request function: 0x%x/0x%x", iorequest->major_func, + iorequest->minor_func); } } -static void guac_rdpdr_device_printer_free_handler(guac_rdp_common_svc* svc, +void guac_rdpdr_device_printer_free_handler(guac_rdp_common_svc* svc, guac_rdpdr_device* device) { Stream_Free(device->device_announce, 1); diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-printer.h b/src/protocols/rdp/channels/rdpdr/rdpdr-printer.h index 0addc6fb..106d6be3 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr-printer.h +++ b/src/protocols/rdp/channels/rdpdr/rdpdr-printer.h @@ -25,6 +25,16 @@ #include +/** + * Name of the printer driver that should be used on the server. + */ +#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" + +/** + * The size of GUAC_PRINTER_DRIVER in bytes. + */ +#define GUAC_PRINTER_DRIVER_LENGTH 50 + /** * Registers a new printer device within the RDPDR plugin. This must be done * before RDPDR connection finishes. @@ -38,5 +48,34 @@ */ void guac_rdpdr_register_printer(guac_rdp_common_svc* svc, char* printer_name); +/** + * I/O request handler which processes a print job creation request. + */ +guac_rdpdr_device_iorequest_handler guac_rdpdr_process_print_job_create; + +/** + * I/O request handler which processes a request to write data to an existing + * print job. + */ +guac_rdpdr_device_iorequest_handler guac_rdpdr_process_print_job_write; + +/** + * I/O request handler which processes a request to close an existing print + * job. + */ +guac_rdpdr_device_iorequest_handler guac_rdpdr_process_print_job_close; + +/** + * Handler for RDPDR Device I/O Requests which processes received messages on + * behalf of a printer device, in this case a simulated printer which produces + * PDF output. + */ +guac_rdpdr_device_iorequest_handler guac_rdpdr_device_printer_iorequest_handler; + +/** + * Free handler which frees all data specific to the simulated printer device. + */ +guac_rdpdr_device_free_handler guac_rdpdr_device_printer_free_handler; + #endif diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr.h b/src/protocols/rdp/channels/rdpdr/rdpdr.h index f75df0f0..19f178d0 100644 --- a/src/protocols/rdp/channels/rdpdr/rdpdr.h +++ b/src/protocols/rdp/channels/rdpdr/rdpdr.h @@ -37,21 +37,79 @@ typedef struct guac_rdpdr_device guac_rdpdr_device; /** - * Handler for client device list announce. Each implementing device must write - * its announcement header and data to the given output stream. + * The contents of the header common to all RDPDR Device I/O Requests. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/a087ffa8-d0d5-4874-ac7b-0494f63e2d5d */ -typedef void guac_rdpdr_device_announce_handler(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* output_stream, int device_id); +typedef struct guac_rdpdr_iorequest { + + /** + * The unique ID assigned to the device receiving this I/O request. + */ + int device_id; + + /** + * The unique ID which identifies the relevant file, as returned when the + * file was opened. This field may not be relevant to all requests. + */ + int file_id; + + /** + * The unique ID that should be used to refer to this I/O request in future + * responses. + */ + int completion_id; + + /** + * Integer ID which identifies the function being requested, such as + * IRP_MJ_CREATE (open a file within a shared drive) or IRP_MJ_WRITE (write + * data to an open file). + */ + int major_func; + + /** + * Integer ID which identifies a variant of the function denoted by + * major_func. This value is only valid for IRP_MJ_DIRECTORY_CONTROL. + */ + int minor_func; + +} guac_rdpdr_iorequest; /** - * Handler for device I/O requests. + * Handler for Device I/O Requests. RDPDR devices must provide an + * implementation of this function to be able to handle inbound I/O requests. + * + * @param svc + * The guac_rdp_common_svc representing the static virtual channel being + * used for RDPDR. + * + * @param device + * The guac_rdpdr_device of the relevant device, as dictated by the + * deviceId field of common RDPDR header within the received PDU. Within + * the guac_rdpdr_iorequest structure, the deviceId field is stored within + * device_id. + * + * @param iorequest + * The contents of the common RDPDR Device I/O Request header shared by all + * RDPDR devices. + * + * @param input_stream + * The remaining data within the received PDU, following the common RDPDR + * Device I/O Request header. */ typedef void guac_rdpdr_device_iorequest_handler(guac_rdp_common_svc* svc, - guac_rdpdr_device* device, wStream* input_stream, int file_id, - int completion_id, int major_func, int minor_func); + guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest, + wStream* input_stream); /** * Handler for cleaning up the dynamically-allocated portions of a device. + * + * @param svc + * The guac_rdp_common_svc representing the static virtual channel being + * used for RDPDR. + * + * @param device + * The guac_rdpdr_device of the device being freed. */ typedef void guac_rdpdr_device_free_handler(guac_rdp_common_svc* svc, guac_rdpdr_device* device); @@ -126,7 +184,30 @@ typedef struct guac_rdpdr { /** * Creates a new stream which contains the common DR_DEVICE_IOCOMPLETION header - * used for virtually all responses. + * used for virtually all responses. Depending on the specific I/O completion + * being sent, additional space may be reserved within the resulting stream for + * additional fields. See: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/10ef9ada-cba2-4384-ab60-7b6290ed4a9a + * + * @param device + * The device that completed the operation requested by a prior I/O + * request. + * + * @param completion_id + * The completion ID of the I/O request that requested the operation. + * + * @param status + * An NTSTATUS code describing the success/failure of the operation that + * was completed. + * + * @param size + * The number of additional bytes to reserve at the end of the resulting + * stream for additional fields to be appended. + * + * @return + * A new wStream containing an I/O completion header, followed by the + * requested additional free space. */ wStream* guac_rdpdr_new_io_completion(guac_rdpdr_device* device, int completion_id, int status, int size);