GUACAMOLE-249: Refactor RDPDR to be more documentable. Document RDPDR fully.

This commit is contained in:
Michael Jumper 2019-12-29 18:04:27 -08:00
parent 36545cc92c
commit d2083a1aed
15 changed files with 625 additions and 393 deletions

View File

@ -18,6 +18,7 @@
*/ */
#include "config.h" #include "config.h"
#include "channels/rdpdr/rdpdr-fs-messages-dir-info.h"
#include "channels/rdpdr/rdpdr.h" #include "channels/rdpdr/rdpdr.h"
#include "fs.h" #include "fs.h"
#include "unicode.h" #include "unicode.h"
@ -29,8 +30,8 @@
#include <stddef.h> #include <stddef.h>
void guac_rdpdr_fs_process_query_directory_info(guac_rdp_common_svc* svc, void guac_rdpdr_fs_process_query_directory_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, const char* entry_name, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { const char* entry_name, int entry_file_id) {
guac_rdp_fs_file* file; 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)); (char*) utf16_entry_name, sizeof(utf16_entry_name));
/* Get 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, entry_file_id);
if (file == NULL) if (file == NULL)
return; return;
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG,
"%s: [file_id=%i (entry_name=\"%s\")]", "%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, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 4 + 64 + utf16_length + 2); iorequest->completion_id, STATUS_SUCCESS,
4 + 64 + utf16_length + 2);
Stream_Write_UINT32(output_stream, Stream_Write_UINT32(output_stream,
64 + utf16_length + 2); /* Length */ 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, 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, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { const char* entry_name, int entry_file_id) {
guac_rdp_fs_file* file; 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)); (char*) utf16_entry_name, sizeof(utf16_entry_name));
/* Get 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, entry_file_id);
if (file == NULL) if (file == NULL)
return; return;
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG,
"%s: [file_id=%i (entry_name=\"%s\")]", "%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, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 4 + 68 + utf16_length + 2); iorequest->completion_id, STATUS_SUCCESS,
4 + 68 + utf16_length + 2);
Stream_Write_UINT32(output_stream, Stream_Write_UINT32(output_stream,
68 + utf16_length + 2); /* Length */ 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, 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, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { const char* entry_name, int entry_file_id) {
guac_rdp_fs_file* file; 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)); (char*) utf16_entry_name, sizeof(utf16_entry_name));
/* Get 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, entry_file_id);
if (file == NULL) if (file == NULL)
return; return;
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG,
"%s: [file_id=%i (entry_name=\"%s\")]", "%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, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 4 + 69 + 24 + utf16_length + 2); iorequest->completion_id, STATUS_SUCCESS,
4 + 69 + 24 + utf16_length + 2);
Stream_Write_UINT32(output_stream, Stream_Write_UINT32(output_stream,
69 + 24 + utf16_length + 2); /* Length */ 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, void guac_rdpdr_fs_process_query_names_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, const char* entry_name, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { const char* entry_name, int entry_file_id) {
guac_rdp_fs_file* file; 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)); (char*) utf16_entry_name, sizeof(utf16_entry_name));
/* Get 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, entry_file_id);
if (file == NULL) if (file == NULL)
return; return;
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG,
"%s: [file_id=%i (entry_name=\"%s\")]", "%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, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 4 + 12 + utf16_length + 2); iorequest->completion_id, STATUS_SUCCESS,
4 + 12 + utf16_length + 2);
Stream_Write_UINT32(output_stream, Stream_Write_UINT32(output_stream,
12 + utf16_length + 2); /* Length */ 12 + utf16_length + 2); /* Length */

View File

@ -34,40 +34,60 @@
#include <winpr/stream.h> #include <winpr/stream.h>
/**
* 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 * Processes a query request for FileDirectoryInformation. From the
* documentation this is "defined as the file's name, time stamp, and size, or its * documentation this is "defined as the file's name, time stamp, and size, or its
* attributes." * attributes."
*/ */
void guac_rdpdr_fs_process_query_directory_info(guac_rdp_common_svc* svc, guac_rdpdr_directory_query_handler guac_rdpdr_fs_process_query_directory_info;
guac_rdpdr_device* device, const char* entry_name, int file_id,
int completion_id);
/** /**
* Processes a query request for FileFullDirectoryInformation. From the * Processes a query request for FileFullDirectoryInformation. From the
* documentation, this is "defined as all the basic information, plus extended * documentation, this is "defined as all the basic information, plus extended
* attribute size." * attribute size."
*/ */
void guac_rdpdr_fs_process_query_full_directory_info(guac_rdp_common_svc* svc, guac_rdpdr_directory_query_handler guac_rdpdr_fs_process_query_full_directory_info;
guac_rdpdr_device* device, const char* entry_name, int file_id,
int completion_id);
/** /**
* Processes a query request for FileBothDirectoryInformation. From the * Processes a query request for FileBothDirectoryInformation. From the
* documentation, this absurdly-named request is "basic information plus * documentation, this absurdly-named request is "basic information plus
* extended attribute size and short name about a file or directory." * 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_directory_query_handler guac_rdpdr_fs_process_query_both_directory_info;
guac_rdpdr_device* device, const char* entry_name, int file_id,
int completion_id);
/** /**
* Processes a query request for FileNamesInformation. From the documentation, * Processes a query request for FileNamesInformation. From the documentation,
* this is "detailed information on the names of files in a directory." * 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_directory_query_handler guac_rdpdr_fs_process_query_names_info;
guac_rdpdr_device* device, const char* entry_name, int file_id,
int completion_id);
#endif #endif

View File

@ -18,6 +18,7 @@
*/ */
#include "config.h" #include "config.h"
#include "channels/rdpdr/rdpdr-fs-messages-file-info.h"
#include "channels/rdpdr/rdpdr.h" #include "channels/rdpdr/rdpdr.h"
#include "fs.h" #include "fs.h"
#include "unicode.h" #include "unicode.h"
@ -31,23 +32,22 @@
#include <string.h> #include <string.h>
void guac_rdpdr_fs_process_query_basic_info(guac_rdp_common_svc* svc, void guac_rdpdr_fs_process_query_basic_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream; wStream* output_stream;
guac_rdp_fs_file* file; guac_rdp_fs_file* file;
/* Get 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) if (file == NULL)
return; return;
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__,
"%s: [file_id=%i]", iorequest->file_id);
__func__, file_id);
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 40); iorequest->completion_id, STATUS_SUCCESS, 40);
Stream_Write_UINT32(output_stream, 36); Stream_Write_UINT32(output_stream, 36);
Stream_Write_UINT64(output_stream, file->ctime); /* CreationTime */ 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, void guac_rdpdr_fs_process_query_standard_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream; wStream* output_stream;
guac_rdp_fs_file* file; guac_rdp_fs_file* file;
BOOL is_directory = FALSE; BOOL is_directory = FALSE;
/* Get 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) if (file == NULL)
return; return;
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__,
"%s: [file_id=%i]", iorequest->file_id);
__func__, file_id);
if (file->attributes & FILE_ATTRIBUTE_DIRECTORY) if (file->attributes & FILE_ATTRIBUTE_DIRECTORY)
is_directory = TRUE; is_directory = TRUE;
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 26); iorequest->completion_id, STATUS_SUCCESS, 26);
Stream_Write_UINT32(output_stream, 22); Stream_Write_UINT32(output_stream, 22);
Stream_Write_UINT64(output_stream, file->size); /* AllocationSize */ 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, void guac_rdpdr_fs_process_query_attribute_tag_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream; wStream* output_stream;
guac_rdp_fs_file* file; guac_rdp_fs_file* file;
/* Get 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) if (file == NULL)
return; return;
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__,
"%s: [file_id=%i]", iorequest->file_id);
__func__, file_id);
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 12); iorequest->completion_id, STATUS_SUCCESS, 12);
Stream_Write_UINT32(output_stream, 8); Stream_Write_UINT32(output_stream, 8);
Stream_Write_UINT32(output_stream, file->attributes); /* FileAttributes */ 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, void guac_rdpdr_fs_process_set_rename_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id, int length) { int length, wStream* input_stream) {
int result; int result;
int filename_length; 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, guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), filename_length/2,
destination_path, sizeof(destination_path)); destination_path, sizeof(destination_path));
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]"
"%s: [file_id=%i] destination_path=\"%s\"", "destination_path=\"%s\"", __func__, iorequest->file_id,
__func__, file_id, destination_path); destination_path);
/* If file moving to \Download folder, start stream, do not move */ /* If file moving to \Download folder, start stream, do not move */
if (strncmp(destination_path, "\\Download\\", 10) == 0) { 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; guac_rdp_fs_file* file;
/* Get 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) if (file == NULL)
return; return;
/* Initiate download, pretend move succeeded */ /* Initiate download, pretend move succeeded */
guac_rdpdr_start_download(svc, device, file->absolute_path); guac_rdpdr_start_download(svc, device, file->absolute_path);
output_stream = guac_rdpdr_new_io_completion(device, output_stream = guac_rdpdr_new_io_completion(device,
completion_id, STATUS_SUCCESS, 4); iorequest->completion_id, STATUS_SUCCESS, 4);
} }
/* Otherwise, rename as requested */ /* Otherwise, rename as requested */
else { else {
result = guac_rdp_fs_rename((guac_rdp_fs*) device->data, file_id, result = guac_rdp_fs_rename((guac_rdp_fs*) device->data,
destination_path); iorequest->file_id, destination_path);
if (result < 0) if (result < 0)
output_stream = guac_rdpdr_new_io_completion(device, 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 else
output_stream = guac_rdpdr_new_io_completion(device, 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, void guac_rdpdr_fs_process_set_allocation_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id, int length) { int length, wStream* input_stream) {
int result; int result;
UINT64 size; UINT64 size;
@ -196,18 +194,17 @@ void guac_rdpdr_fs_process_set_allocation_info(guac_rdp_common_svc* svc,
/* Read new size */ /* Read new size */
Stream_Read_UINT64(input_stream, size); /* AllocationSize */ Stream_Read_UINT64(input_stream, size); /* AllocationSize */
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] "
"%s: [file_id=%i] size=%" PRIu64, "size=%" PRIu64, __func__, iorequest->file_id, (uint64_t) size);
__func__, file_id, (uint64_t) size);
/* Truncate file */ /* 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) if (result < 0)
output_stream = guac_rdpdr_new_io_completion(device, 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 else
output_stream = guac_rdpdr_new_io_completion(device, 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); Stream_Write_UINT32(output_stream, length);
guac_rdp_common_svc_write(svc, output_stream); 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, void guac_rdpdr_fs_process_set_disposition_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id, int length) { int length, wStream* input_stream) {
wStream* output_stream; wStream* output_stream;
/* Delete file */ /* 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) if (result < 0)
output_stream = guac_rdpdr_new_io_completion(device, 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 else
output_stream = guac_rdpdr_new_io_completion(device, 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, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__,
"%s: [file_id=%i]", iorequest->file_id);
__func__, file_id);
Stream_Write_UINT32(output_stream, length); 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, 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, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id, int length) { int length, wStream* input_stream) {
int result; int result;
UINT64 size; UINT64 size;
@ -250,18 +246,17 @@ void guac_rdpdr_fs_process_set_end_of_file_info(guac_rdp_common_svc* svc,
/* Read new size */ /* Read new size */
Stream_Read_UINT64(input_stream, size); /* AllocationSize */ Stream_Read_UINT64(input_stream, size); /* AllocationSize */
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] "
"%s: [file_id=%i] size=%" PRIu64, "size=%" PRIu64, __func__, iorequest->file_id, (uint64_t) size);
__func__, file_id, (uint64_t) size);
/* Truncate file */ /* 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) if (result < 0)
output_stream = guac_rdpdr_new_io_completion(device, 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 else
output_stream = guac_rdpdr_new_io_completion(device, 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); Stream_Write_UINT32(output_stream, length);
guac_rdp_common_svc_write(svc, output_stream); 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, void guac_rdpdr_fs_process_set_basic_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id, int length) { int length, wStream* input_stream) {
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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 */ /* Currently do nothing, just respond */
Stream_Write_UINT32(output_stream, length); Stream_Write_UINT32(output_stream, length);
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] IGNORED",
"%s: [file_id=%i] IGNORED", __func__, iorequest->file_id);
__func__, file_id);
guac_rdp_common_svc_write(svc, output_stream); guac_rdp_common_svc_write(svc, output_stream);

View File

@ -33,72 +33,88 @@
#include <winpr/stream.h> #include <winpr/stream.h>
/**
* 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 * Processes a query for FileBasicInformation. From the documentation, this is
* "used to query a file for the times of creation, last access, last write, * "used to query a file for the times of creation, last access, last write,
* and change, in addition to file attribute information." * and change, in addition to file attribute information."
*/ */
void guac_rdpdr_fs_process_query_basic_info(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_basic_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Processes a query for FileStandardInformation. From the documentation, this * Processes a query for FileStandardInformation. From the documentation, this
* is "used to query for file information such as allocation size, end-of-file * is "used to query for file information such as allocation size, end-of-file
* position, and number of links." * position, and number of links."
*/ */
void guac_rdpdr_fs_process_query_standard_info(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_standard_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Processes a query for FileAttributeTagInformation. From the documentation * Processes a query for FileAttributeTagInformation. From the documentation
* this is "used to query for file attribute and reparse tag information." * 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_iorequest_handler guac_rdpdr_fs_process_query_attribute_tag_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Process a set operation for FileRenameInformation. From the documentation, * Process a set operation for FileRenameInformation. From the documentation,
* this operation is used to rename a file. * this operation is used to rename a file.
*/ */
void guac_rdpdr_fs_process_set_rename_info(guac_rdp_common_svc* svc, guac_rdpdr_set_information_request_handler guac_rdpdr_fs_process_set_rename_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id, int length);
/** /**
* Process a set operation for FileAllocationInformation. From the * Process a set operation for FileAllocationInformation. From the
* documentation, this operation is used to set a file's allocation size. * 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_set_information_request_handler guac_rdpdr_fs_process_set_allocation_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id, int length);
/** /**
* Process a set operation for FileDispositionInformation. From the * Process a set operation for FileDispositionInformation. From the
* documentation, this operation is used to mark a file for deletion. * 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_set_information_request_handler guac_rdpdr_fs_process_set_disposition_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id, int length);
/** /**
* Process a set operation for FileEndOfFileInformation. From the * Process a set operation for FileEndOfFileInformation. From the
* documentation, this operation is used "to set end-of-file information for * documentation, this operation is used "to set end-of-file information for
* a file." * a file."
*/ */
void guac_rdpdr_fs_process_set_end_of_file_info(guac_rdp_common_svc* svc, guac_rdpdr_set_information_request_handler guac_rdpdr_fs_process_set_end_of_file_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id, int length);
/** /**
* Process a set operation for FileBasicInformation. From the documentation, * Process a set operation for FileBasicInformation. From the documentation,
* this is "used to set file information such as the times of creation, last * this is "used to set file information such as the times of creation, last
* access, last write, and change, in addition to file attributes." * 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_set_information_request_handler guac_rdpdr_fs_process_set_basic_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id, int length);
#endif #endif

View File

@ -19,6 +19,8 @@
#include "config.h" #include "config.h"
#include "channels/rdpdr/rdpdr-messages.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 "channels/rdpdr/rdpdr.h"
#include "fs.h" #include "fs.h"
@ -28,15 +30,14 @@
#include <winpr/wtypes.h> #include <winpr/wtypes.h>
void guac_rdpdr_fs_process_query_volume_info(guac_rdp_common_svc* svc, void guac_rdpdr_fs_process_query_volume_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__,
"%s: [file_id=%i]", iorequest->file_id);
__func__, file_id);
Stream_Write_UINT32(output_stream, 17 + GUAC_FILESYSTEM_LABEL_LENGTH); Stream_Write_UINT32(output_stream, 17 + GUAC_FILESYSTEM_LABEL_LENGTH);
Stream_Write_UINT64(output_stream, 0); /* VolumeCreationTime */ 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, void guac_rdpdr_fs_process_query_size_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
guac_rdp_fs_info info = {0}; guac_rdp_fs_info info = {0};
guac_rdp_fs_get_info((guac_rdp_fs*) device->data, &info); guac_rdp_fs_get_info((guac_rdp_fs*) device->data, &info);
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__,
"%s: [file_id=%i]", iorequest->file_id);
__func__, file_id);
Stream_Write_UINT32(output_stream, 24); Stream_Write_UINT32(output_stream, 24);
Stream_Write_UINT64(output_stream, info.blocks_total); /* TotalAllocationUnits */ 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, void guac_rdpdr_fs_process_query_device_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__,
"%s: [file_id=%i]", iorequest->file_id);
__func__, file_id);
Stream_Write_UINT32(output_stream, 8); Stream_Write_UINT32(output_stream, 8);
Stream_Write_UINT32(output_stream, FILE_DEVICE_DISK); /* DeviceType */ 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, void guac_rdpdr_fs_process_query_attribute_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
int name_len = guac_utf8_strlen(device->device_name); int name_len = guac_utf8_strlen(device->device_name);
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__,
"%s: [file_id=%i]", iorequest->file_id);
__func__, file_id);
Stream_Write_UINT32(output_stream, 12 + name_len); Stream_Write_UINT32(output_stream, 12 + name_len);
Stream_Write_UINT32(output_stream, 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, void guac_rdpdr_fs_process_query_full_size_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
guac_rdp_fs_info info = {0}; guac_rdp_fs_info info = {0};
guac_rdp_fs_get_info((guac_rdp_fs*) device->data, &info); guac_rdp_fs_get_info((guac_rdp_fs*) device->data, &info);
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__,
"%s: [file_id=%i]", iorequest->file_id);
__func__, file_id);
Stream_Write_UINT32(output_stream, 32); Stream_Write_UINT32(output_stream, 32);
Stream_Write_UINT64(output_stream, info.blocks_total); /* TotalAllocationUnits */ Stream_Write_UINT64(output_stream, info.blocks_total); /* TotalAllocationUnits */

View File

@ -38,37 +38,27 @@
* documentation, this is "used to query information for a volume on which a * documentation, this is "used to query information for a volume on which a
* file system is mounted." * file system is mounted."
*/ */
void guac_rdpdr_fs_process_query_volume_info(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_volume_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Processes a query request for FileFsSizeInformation. * Processes a query request for FileFsSizeInformation.
*/ */
void guac_rdpdr_fs_process_query_size_info(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_size_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Processes a query request for FileFsAttributeInformation. * Processes a query request for FileFsAttributeInformation.
*/ */
void guac_rdpdr_fs_process_query_attribute_info(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_attribute_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Processes a query request for FileFsFullSizeInformation. * Processes a query request for FileFsFullSizeInformation.
*/ */
void guac_rdpdr_fs_process_query_full_size_info(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_full_size_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Processes a query request for FileFsDeviceInformation. * Processes a query request for FileFsDeviceInformation.
*/ */
void guac_rdpdr_fs_process_query_device_info(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_query_device_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
#endif #endif

View File

@ -39,7 +39,8 @@
#include <string.h> #include <string.h>
void guac_rdpdr_fs_process_create(guac_rdp_common_svc* svc, 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; wStream* output_stream;
int file_id; 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, guac_client_log(svc->client, GUAC_LOG_ERROR,
"File open refused (%i): \"%s\"", file_id, path); "File open refused (%i): \"%s\"", file_id, path);
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
guac_rdp_fs_get_status(file_id), 5); iorequest->completion_id, guac_rdp_fs_get_status(file_id), 5);
Stream_Write_UINT32(output_stream, 0); /* fileId */ Stream_Write_UINT32(output_stream, 0); /* fileId */
Stream_Write_UINT8(output_stream, 0); /* information */ 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; guac_rdp_fs_file* file;
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 5); iorequest->completion_id, STATUS_SUCCESS, 5);
Stream_Write_UINT32(output_stream, file_id); /* fileId */ Stream_Write_UINT32(output_stream, file_id); /* fileId */
Stream_Write_UINT8(output_stream, 0); /* information */ 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, void guac_rdpdr_fs_process_read(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
UINT32 length; UINT32 length;
UINT64 offset; 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, guac_client_log(svc->client, GUAC_LOG_DEBUG,
"%s: [file_id=%i] length=%i, offset=%" PRIu64, "%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 */ /* Ensure buffer size does not exceed a safe maximum */
if (length > GUAC_RDP_MAX_READ_BUFFER) 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); buffer = malloc(length);
/* Attempt read */ /* Attempt read */
bytes_read = guac_rdp_fs_read((guac_rdp_fs*) device->data, file_id, offset, bytes_read = guac_rdp_fs_read((guac_rdp_fs*) device->data,
buffer, length); iorequest->file_id, offset, buffer, length);
/* If error, return invalid parameter */ /* If error, return invalid parameter */
if (bytes_read < 0) { if (bytes_read < 0) {
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
guac_rdp_fs_get_status(bytes_read), 4); iorequest->completion_id, guac_rdp_fs_get_status(bytes_read), 4);
Stream_Write_UINT32(output_stream, 0); /* Length */ Stream_Write_UINT32(output_stream, 0); /* Length */
} }
/* Otherwise, send bytes read */ /* Otherwise, send bytes read */
else { else {
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 4+bytes_read); iorequest->completion_id, STATUS_SUCCESS, 4+bytes_read);
Stream_Write_UINT32(output_stream, bytes_read); /* Length */ Stream_Write_UINT32(output_stream, bytes_read); /* Length */
Stream_Write(output_stream, buffer, bytes_read); /* ReadData */ 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, void guac_rdpdr_fs_process_write(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
UINT32 length; UINT32 length;
UINT64 offset; 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, guac_client_log(svc->client, GUAC_LOG_DEBUG,
"%s: [file_id=%i] length=%i, offset=%" PRIu64, "%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 */ /* Attempt write */
bytes_written = guac_rdp_fs_write((guac_rdp_fs*) device->data, file_id, bytes_written = guac_rdp_fs_write((guac_rdp_fs*) device->data,
offset, Stream_Pointer(input_stream), length); iorequest->file_id, offset, Stream_Pointer(input_stream), length);
/* If error, return invalid parameter */ /* If error, return invalid parameter */
if (bytes_written < 0) { if (bytes_written < 0) {
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
guac_rdp_fs_get_status(bytes_written), 5); iorequest->completion_id, guac_rdp_fs_get_status(bytes_written), 5);
Stream_Write_UINT32(output_stream, 0); /* Length */ Stream_Write_UINT32(output_stream, 0); /* Length */
Stream_Write_UINT8(output_stream, 0); /* Padding */ Stream_Write_UINT8(output_stream, 0); /* Padding */
} }
/* Otherwise, send success */ /* Otherwise, send success */
else { else {
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 5); iorequest->completion_id, STATUS_SUCCESS, 5);
Stream_Write_UINT32(output_stream, bytes_written); /* Length */ Stream_Write_UINT32(output_stream, bytes_written); /* Length */
Stream_Write_UINT8(output_stream, 0); /* Padding */ 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, void guac_rdpdr_fs_process_close(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream; wStream* output_stream;
guac_rdp_fs_file* file; guac_rdp_fs_file* file;
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]",
"%s: [file_id=%i]", __func__, iorequest->file_id);
__func__, file_id);
/* Get 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) if (file == NULL)
return; return;
@ -225,14 +225,14 @@ void guac_rdpdr_fs_process_close(guac_rdp_common_svc* svc,
if (file->bytes_written > 0 && if (file->bytes_written > 0 &&
strncmp(file->absolute_path, "\\Download\\", 10) == 0) { strncmp(file->absolute_path, "\\Download\\", 10) == 0) {
guac_rdpdr_start_download(svc, device, file->absolute_path); 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 */ /* 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, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_SUCCESS, 4); iorequest->completion_id, STATUS_SUCCESS, 4);
Stream_Write(output_stream, "\0\0\0\0", 4); /* Padding */ Stream_Write(output_stream, "\0\0\0\0", 4); /* Padding */
guac_rdp_common_svc_write(svc, output_stream); 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, void guac_rdpdr_fs_process_volume_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
int fs_information_class; int fs_information_class;
@ -251,28 +251,23 @@ void guac_rdpdr_fs_process_volume_info(guac_rdp_common_svc* svc,
switch (fs_information_class) { switch (fs_information_class) {
case FileFsVolumeInformation: case FileFsVolumeInformation:
guac_rdpdr_fs_process_query_volume_info(svc, device, input_stream, guac_rdpdr_fs_process_query_volume_info(svc, device, iorequest, input_stream);
file_id, completion_id);
break; break;
case FileFsSizeInformation: case FileFsSizeInformation:
guac_rdpdr_fs_process_query_size_info(svc, device, input_stream, guac_rdpdr_fs_process_query_size_info(svc, device, iorequest, input_stream);
file_id, completion_id);
break; break;
case FileFsDeviceInformation: case FileFsDeviceInformation:
guac_rdpdr_fs_process_query_device_info(svc, device, input_stream, guac_rdpdr_fs_process_query_device_info(svc, device, iorequest, input_stream);
file_id, completion_id);
break; break;
case FileFsAttributeInformation: case FileFsAttributeInformation:
guac_rdpdr_fs_process_query_attribute_info(svc, device, guac_rdpdr_fs_process_query_attribute_info(svc, device, iorequest, input_stream);
input_stream, file_id, completion_id);
break; break;
case FileFsFullSizeInformation: case FileFsFullSizeInformation:
guac_rdpdr_fs_process_query_full_size_info(svc, device, guac_rdpdr_fs_process_query_full_size_info(svc, device, iorequest, input_stream);
input_stream, file_id, completion_id);
break; break;
default: 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, void guac_rdpdr_fs_process_file_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
int fs_information_class; int fs_information_class;
@ -294,18 +289,15 @@ void guac_rdpdr_fs_process_file_info(guac_rdp_common_svc* svc,
switch (fs_information_class) { switch (fs_information_class) {
case FileBasicInformation: case FileBasicInformation:
guac_rdpdr_fs_process_query_basic_info(svc, device, input_stream, guac_rdpdr_fs_process_query_basic_info(svc, device, iorequest, input_stream);
file_id, completion_id);
break; break;
case FileStandardInformation: case FileStandardInformation:
guac_rdpdr_fs_process_query_standard_info(svc, device, guac_rdpdr_fs_process_query_standard_info(svc, device, iorequest, input_stream);
input_stream, file_id, completion_id);
break; break;
case FileAttributeTagInformation: case FileAttributeTagInformation:
guac_rdpdr_fs_process_query_attribute_tag_info(svc, device, guac_rdpdr_fs_process_query_attribute_tag_info(svc, device, iorequest, input_stream);
input_stream, file_id, completion_id);
break; break;
default: 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, void guac_rdpdr_fs_process_set_volume_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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, guac_client_log(svc->client, GUAC_LOG_DEBUG,
"%s: [file_id=%i] Set volume info not supported", "%s: [file_id=%i] Set volume info not supported",
__func__, file_id); __func__, iorequest->file_id);
guac_rdp_common_svc_write(svc, output_stream); guac_rdp_common_svc_write(svc, output_stream);
} }
void guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc* svc, void guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
int fs_information_class; int fs_information_class;
int length; int length;
@ -345,28 +337,23 @@ void guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc* svc,
switch (fs_information_class) { switch (fs_information_class) {
case FileBasicInformation: case FileBasicInformation:
guac_rdpdr_fs_process_set_basic_info(svc, device, input_stream, guac_rdpdr_fs_process_set_basic_info(svc, device, iorequest, length, input_stream);
file_id, completion_id, length);
break; break;
case FileEndOfFileInformation: case FileEndOfFileInformation:
guac_rdpdr_fs_process_set_end_of_file_info(svc, device, guac_rdpdr_fs_process_set_end_of_file_info(svc, device, iorequest, length, input_stream);
input_stream, file_id, completion_id, length);
break; break;
case FileDispositionInformation: case FileDispositionInformation:
guac_rdpdr_fs_process_set_disposition_info(svc, device, guac_rdpdr_fs_process_set_disposition_info(svc, device, iorequest, length, input_stream);
input_stream, file_id, completion_id, length);
break; break;
case FileRenameInformation: case FileRenameInformation:
guac_rdpdr_fs_process_set_rename_info(svc, device, input_stream, guac_rdpdr_fs_process_set_rename_info(svc, device, iorequest, length, input_stream);
file_id, completion_id, length);
break; break;
case FileAllocationInformation: case FileAllocationInformation:
guac_rdpdr_fs_process_set_allocation_info(svc, device, guac_rdpdr_fs_process_set_allocation_info(svc, device, iorequest, length, input_stream);
input_stream, file_id, completion_id, length);
break; break;
default: 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, void guac_rdpdr_fs_process_device_control(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] IGNORED",
"%s: [file_id=%i] IGNORED", __func__, iorequest->file_id);
__func__, file_id);
/* No content for now */ /* No content for now */
Stream_Write_UINT32(output_stream, 0); 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, void guac_rdpdr_fs_process_notify_change_directory(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
guac_client_log(svc->client, GUAC_LOG_DEBUG, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] Not "
"%s: [file_id=%i] Not implemented", "implemented", __func__, iorequest->file_id);
__func__, file_id);
} }
void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc, void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream; wStream* output_stream;
@ -418,7 +403,7 @@ void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc,
const char* entry_name; const char* entry_name;
/* Get 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) if (file == NULL)
return; 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, guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] "
"%s: [file_id=%i] initial_query=%i, dir_pattern=\"%s\"", "initial_query=%i, dir_pattern=\"%s\"", __func__,
__func__, file_id, initial_query, file->dir_pattern); iorequest->file_id, initial_query, file->dir_pattern);
/* Find first matching entry in directory */ /* Find first matching entry in directory */
while ((entry_name = guac_rdp_fs_read_dir((guac_rdp_fs*) device->data, while ((entry_name = guac_rdp_fs_read_dir((guac_rdp_fs*) device->data,
file_id)) != NULL) { iorequest->file_id)) != NULL) {
/* Convert to absolute path */ /* Convert to absolute path */
char entry_path[GUAC_RDP_FS_MAX_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: case FileDirectoryInformation:
guac_rdpdr_fs_process_query_directory_info(svc, device, guac_rdpdr_fs_process_query_directory_info(svc, device,
entry_name, entry_file_id, completion_id); iorequest, entry_name, entry_file_id);
break; break;
case FileFullDirectoryInformation: case FileFullDirectoryInformation:
guac_rdpdr_fs_process_query_full_directory_info(svc, guac_rdpdr_fs_process_query_full_directory_info(svc,
device, entry_name, entry_file_id, device, iorequest, entry_name, entry_file_id);
completion_id);
break; break;
case FileBothDirectoryInformation: case FileBothDirectoryInformation:
guac_rdpdr_fs_process_query_both_directory_info(svc, guac_rdpdr_fs_process_query_both_directory_info(svc,
device, entry_name, entry_file_id, device, iorequest, entry_name, entry_file_id);
completion_id);
break; break;
case FileNamesInformation: case FileNamesInformation:
guac_rdpdr_fs_process_query_names_info(svc, device, guac_rdpdr_fs_process_query_names_info(svc, device,
entry_name, entry_file_id, completion_id); iorequest, entry_name, entry_file_id);
break; break;
default: default:
@ -505,8 +488,8 @@ void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc,
* Handle errors as a lack of files. * Handle errors as a lack of files.
*/ */
output_stream = guac_rdpdr_new_io_completion(device, completion_id, output_stream = guac_rdpdr_new_io_completion(device,
STATUS_NO_MORE_FILES, 5); iorequest->completion_id, STATUS_NO_MORE_FILES, 5);
Stream_Write_UINT32(output_stream, 0); /* Length */ Stream_Write_UINT32(output_stream, 0); /* Length */
Stream_Write_UINT8(output_stream, 0); /* Padding */ 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, void guac_rdpdr_fs_process_lock_control(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id) { wStream* input_stream) {
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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, guac_client_log(svc->client, GUAC_LOG_DEBUG,
"%s: [file_id=%i] Lock not supported", "%s: [file_id=%i] Lock not supported",
__func__, file_id); __func__, iorequest->file_id);
Stream_Zero(output_stream, 5); /* Padding */ Stream_Zero(output_stream, 5); /* Padding */

View File

@ -37,37 +37,28 @@
* Handles a Server Create Drive Request. Despite its name, this request opens * Handles a Server Create Drive Request. Despite its name, this request opens
* a file. * a file.
*/ */
void guac_rdpdr_fs_process_create(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_create;
guac_rdpdr_device* device, wStream* input_stream, int completion_id);
/** /**
* 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_iorequest_handler guac_rdpdr_fs_process_close;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive Read Request. This request reads from a file. * 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_iorequest_handler guac_rdpdr_fs_process_read;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive Write Request. This request writes to a file. * 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_iorequest_handler guac_rdpdr_fs_process_write;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive Control Request. This request handles one of any * Handles a Server Drive Control Request. This request handles one of any
* number of Windows FSCTL_* control functions. * number of Windows FSCTL_* control functions.
*/ */
void guac_rdpdr_fs_process_device_control(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_device_control;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive Query Volume Information Request. This request * 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 * has several query types which have their own handlers defined in a
* separate file. * separate file.
*/ */
void guac_rdpdr_fs_process_volume_info(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_volume_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive Set Volume Information Request. Currently, this * Handles a Server Drive Set Volume Information Request. Currently, this
* RDPDR implementation does not support setting of volume information. * 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_iorequest_handler guac_rdpdr_fs_process_set_volume_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive Query Information Request. This request queries * Handles a Server Drive Query Information Request. This request queries
* information about a specific file. This request has several query types * information about a specific file. This request has several query types
* which have their own handlers defined in a separate file. * 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_iorequest_handler guac_rdpdr_fs_process_file_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive Set Information Request. This request sets * Handles a Server Drive Set Information Request. This request sets
* information about a specific file. Currently, this RDPDR implementation does * information about a specific file. Currently, this RDPDR implementation does
* not support setting of file information. * not support setting of file information.
*/ */
void guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_set_file_info;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive Query Directory Request. This request queries * Handles a Server Drive Query Directory Request. This request queries
* information about a specific directory. This request has several query types * information about a specific directory. This request has several query types
* which have their own handlers defined in a separate file. * 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_iorequest_handler guac_rdpdr_fs_process_query_directory;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive NotifyChange Directory Request. This request requests * Handles a Server Drive NotifyChange Directory Request. This request requests
* directory change notification. * directory change notification.
*/ */
void guac_rdpdr_fs_process_notify_change_directory(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_notify_change_directory;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
/** /**
* Handles a Server Drive Lock Control Request. This request locks or unlocks * Handles a Server Drive Lock Control Request. This request locks or unlocks
* portions of a file. * portions of a file.
*/ */
void guac_rdpdr_fs_process_lock_control(guac_rdp_common_svc* svc, guac_rdpdr_device_iorequest_handler guac_rdpdr_fs_process_lock_control;
guac_rdpdr_device* device, wStream* input_stream, int file_id,
int completion_id);
#endif #endif

View File

@ -19,6 +19,7 @@
#include "config.h" #include "config.h"
#include "channels/rdpdr/rdpdr-fs-messages.h" #include "channels/rdpdr/rdpdr-fs-messages.h"
#include "channels/rdpdr/rdpdr-fs.h"
#include "channels/rdpdr/rdpdr-messages.h" #include "channels/rdpdr/rdpdr-messages.h"
#include "channels/rdpdr/rdpdr.h" #include "channels/rdpdr/rdpdr.h"
#include "rdp.h" #include "rdp.h"
@ -30,96 +31,85 @@
#include <guacamole/unicode.h> #include <guacamole/unicode.h>
#include <winpr/stream.h> #include <winpr/stream.h>
static void guac_rdpdr_device_fs_iorequest_handler(guac_rdp_common_svc* svc, void guac_rdpdr_device_fs_iorequest_handler(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id, int major_func, int minor_func) { wStream* input_stream) {
switch (major_func) { switch (iorequest->major_func) {
/* File open */ /* File open */
case IRP_MJ_CREATE: case IRP_MJ_CREATE:
guac_rdpdr_fs_process_create(svc, device, input_stream, guac_rdpdr_fs_process_create(svc, device, iorequest, input_stream);
completion_id);
break; break;
/* File close */ /* File close */
case IRP_MJ_CLOSE: case IRP_MJ_CLOSE:
guac_rdpdr_fs_process_close(svc, device, input_stream, file_id, guac_rdpdr_fs_process_close(svc, device, iorequest, input_stream);
completion_id);
break; break;
/* File read */ /* File read */
case IRP_MJ_READ: case IRP_MJ_READ:
guac_rdpdr_fs_process_read(svc, device, input_stream, file_id, guac_rdpdr_fs_process_read(svc, device, iorequest, input_stream);
completion_id);
break; break;
/* File write */ /* File write */
case IRP_MJ_WRITE: case IRP_MJ_WRITE:
guac_rdpdr_fs_process_write(svc, device, input_stream, file_id, guac_rdpdr_fs_process_write(svc, device, iorequest, input_stream);
completion_id);
break; break;
/* Device control request (Windows FSCTL_ control codes) */ /* Device control request (Windows FSCTL_ control codes) */
case IRP_MJ_DEVICE_CONTROL: case IRP_MJ_DEVICE_CONTROL:
guac_rdpdr_fs_process_device_control(svc, device, input_stream, guac_rdpdr_fs_process_device_control(svc, device, iorequest, input_stream);
file_id, completion_id);
break; break;
/* Query volume (drive) information */ /* Query volume (drive) information */
case IRP_MJ_QUERY_VOLUME_INFORMATION: case IRP_MJ_QUERY_VOLUME_INFORMATION:
guac_rdpdr_fs_process_volume_info(svc, device, input_stream, guac_rdpdr_fs_process_volume_info(svc, device, iorequest, input_stream);
file_id, completion_id);
break; break;
/* Set volume (drive) information */ /* Set volume (drive) information */
case IRP_MJ_SET_VOLUME_INFORMATION: case IRP_MJ_SET_VOLUME_INFORMATION:
guac_rdpdr_fs_process_set_volume_info(svc, device, input_stream, guac_rdpdr_fs_process_set_volume_info(svc, device, iorequest, input_stream);
file_id, completion_id);
break; break;
/* Query file information */ /* Query file information */
case IRP_MJ_QUERY_INFORMATION: case IRP_MJ_QUERY_INFORMATION:
guac_rdpdr_fs_process_file_info(svc, device, input_stream, file_id, guac_rdpdr_fs_process_file_info(svc, device, iorequest, input_stream);
completion_id);
break; break;
/* Set file information */ /* Set file information */
case IRP_MJ_SET_INFORMATION: case IRP_MJ_SET_INFORMATION:
guac_rdpdr_fs_process_set_file_info(svc, device, input_stream, guac_rdpdr_fs_process_set_file_info(svc, device, iorequest, input_stream);
file_id, completion_id);
break; break;
case IRP_MJ_DIRECTORY_CONTROL: case IRP_MJ_DIRECTORY_CONTROL:
/* Enumerate directory contents */ /* Enumerate directory contents */
if (minor_func == IRP_MN_QUERY_DIRECTORY) if (iorequest->minor_func == IRP_MN_QUERY_DIRECTORY)
guac_rdpdr_fs_process_query_directory(svc, device, guac_rdpdr_fs_process_query_directory(svc, device, iorequest,
input_stream, file_id, completion_id); input_stream);
/* Request notification of changes to directory */ /* 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, guac_rdpdr_fs_process_notify_change_directory(svc, device,
input_stream, iorequest, input_stream);
file_id, completion_id);
break; break;
/* Lock/unlock portions of a file */ /* Lock/unlock portions of a file */
case IRP_MJ_LOCK_CONTROL: case IRP_MJ_LOCK_CONTROL:
guac_rdpdr_fs_process_lock_control(svc, device, input_stream, guac_rdpdr_fs_process_lock_control(svc, device, iorequest, input_stream);
file_id, completion_id);
break; break;
default: default:
guac_client_log(svc->client, GUAC_LOG_ERROR, guac_client_log(svc->client, GUAC_LOG_ERROR,
"Unknown filesystem I/O request function: 0x%x/0x%x", "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) { guac_rdpdr_device* device) {
Stream_Free(device->device_announce, 1); Stream_Free(device->device_announce, 1);

View File

@ -36,6 +36,16 @@
#include <guacamole/pool.h> #include <guacamole/pool.h>
/**
* 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 * Registers a new filesystem device within the RDPDR plugin. This must be done
* before RDPDR connection finishes. * before RDPDR connection finishes.

View File

@ -31,6 +31,28 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/**
* 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, static void guac_rdpdr_send_client_announce_reply(guac_rdp_common_svc* svc,
unsigned int major, unsigned int minor, unsigned int client_id) { 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, static void guac_rdpdr_send_client_name_request(guac_rdp_common_svc* svc,
const char* name) { 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) { static void guac_rdpdr_send_client_capability(guac_rdp_common_svc* svc) {
wStream* output_stream = Stream_New(NULL, 256); 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) { static void guac_rdpdr_send_client_device_list_announce_request(guac_rdp_common_svc* svc) {
guac_rdpdr* rdpdr = (guac_rdpdr*) svc->data; 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) { wStream* input_stream) {
guac_rdpdr* rdpdr = (guac_rdpdr*) svc->data; guac_rdpdr* rdpdr = (guac_rdpdr*) svc->data;
guac_rdpdr_iorequest iorequest;
int device_id, file_id, completion_id, major_func, minor_func;
/* Read header */ /* Read header */
Stream_Read_UINT32(input_stream, device_id); Stream_Read_UINT32(input_stream, iorequest.device_id);
Stream_Read_UINT32(input_stream, file_id); Stream_Read_UINT32(input_stream, iorequest.file_id);
Stream_Read_UINT32(input_stream, completion_id); Stream_Read_UINT32(input_stream, iorequest.completion_id);
Stream_Read_UINT32(input_stream, major_func); Stream_Read_UINT32(input_stream, iorequest.major_func);
Stream_Read_UINT32(input_stream, minor_func); Stream_Read_UINT32(input_stream, iorequest.minor_func);
/* If printer, run printer handlers */ /* 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 */ /* Call handler on device */
guac_rdpdr_device* device = &(rdpdr->devices[device_id]); guac_rdpdr_device* device = &(rdpdr->devices[iorequest.device_id]);
device->iorequest_handler(svc, device, input_stream, device->iorequest_handler(svc, device, &iorequest, input_stream);
file_id, completion_id, major_func, minor_func);
} }
else 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);
} }

View File

@ -35,29 +35,102 @@
#define GUAC_OS_TYPE (*((uint32_t*) "GUAC")) #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" typedef void guac_rdpdr_message_handler(guac_rdp_common_svc* svc,
#define GUAC_PRINTER_DRIVER_LENGTH 50 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" guac_rdpdr_message_handler guac_rdpdr_process_server_announce;
#define GUAC_FILESYSTEM_LABEL_LENGTH 16
/* /**
* 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); * Handler which processes a received Server Device Announce Response message.
void guac_rdpdr_process_device_reply(guac_rdp_common_svc* svc, wStream* input_stream); * The Server Device Announce Response message is sent in response to a Client
void guac_rdpdr_process_device_iorequest(guac_rdp_common_svc* svc, wStream* input_stream); * Device List Announce message to communicate the success/failure status of
void guac_rdpdr_process_server_capability(guac_rdp_common_svc* svc, wStream* input_stream); * device creation. See:
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); * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/a4c0b619-6e87-4721-bdc4-5d2db7f485f3
void guac_rdpdr_process_prn_using_xps(guac_rdp_common_svc* svc, wStream* input_stream); */
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 #endif

View File

@ -43,7 +43,8 @@
#include <unistd.h> #include <unistd.h>
void guac_rdpdr_process_print_job_create(guac_rdp_common_svc* svc, 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_client* client = svc->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; 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 */ /* Respond with success */
wStream* output_stream = guac_rdpdr_new_io_completion(device, 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 */ Stream_Write_UINT32(output_stream, 0); /* fileId */
guac_rdp_common_svc_write(svc, output_stream); 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, 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_client* client = svc->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; 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, 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_UINT32(output_stream, length);
Stream_Write_UINT8(output_stream, 0); /* Padding */ 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, 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_client* client = svc->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; 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, 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 */ Stream_Write_UINT32(output_stream, 0); /* Padding */
guac_rdp_common_svc_write(svc, output_stream); 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, void guac_rdpdr_device_printer_iorequest_handler(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id, int major_func, int minor_func) { wStream* input_stream) {
switch (major_func) { switch (iorequest->major_func) {
/* Print job create */ /* Print job create */
case IRP_MJ_CREATE: case IRP_MJ_CREATE:
guac_rdpdr_process_print_job_create(svc, device, input_stream, guac_rdpdr_process_print_job_create(svc, device, iorequest, input_stream);
completion_id);
break; break;
/* Printer job write */ /* Printer job write */
case IRP_MJ_WRITE: case IRP_MJ_WRITE:
guac_rdpdr_process_print_job_write(svc, device, input_stream, guac_rdpdr_process_print_job_write(svc, device, iorequest, input_stream);
completion_id);
break; break;
/* Printer job close */ /* Printer job close */
case IRP_MJ_CLOSE: case IRP_MJ_CLOSE:
guac_rdpdr_process_print_job_close(svc, device, input_stream, guac_rdpdr_process_print_job_close(svc, device, iorequest, input_stream);
completion_id);
break; break;
/* Log unknown */ /* Log unknown */
default: default:
guac_client_log(svc->client, GUAC_LOG_ERROR, guac_client_log(svc->client, GUAC_LOG_ERROR, "Unknown printer "
"Unknown printer I/O request function: 0x%x/0x%x", "I/O request function: 0x%x/0x%x", iorequest->major_func,
major_func, minor_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) { guac_rdpdr_device* device) {
Stream_Free(device->device_announce, 1); Stream_Free(device->device_announce, 1);

View File

@ -25,6 +25,16 @@
#include <winpr/stream.h> #include <winpr/stream.h>
/**
* 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 * Registers a new printer device within the RDPDR plugin. This must be done
* before RDPDR connection finishes. * before RDPDR connection finishes.
@ -38,5 +48,34 @@
*/ */
void guac_rdpdr_register_printer(guac_rdp_common_svc* svc, char* printer_name); 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 #endif

View File

@ -37,21 +37,79 @@
typedef struct guac_rdpdr_device guac_rdpdr_device; typedef struct guac_rdpdr_device guac_rdpdr_device;
/** /**
* Handler for client device list announce. Each implementing device must write * The contents of the header common to all RDPDR Device I/O Requests. See:
* its announcement header and data to the given output stream. *
* 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, typedef struct guac_rdpdr_iorequest {
guac_rdpdr_device* device, wStream* output_stream, int device_id);
/** /**
* Handler for device I/O requests. * 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. 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, typedef void guac_rdpdr_device_iorequest_handler(guac_rdp_common_svc* svc,
guac_rdpdr_device* device, wStream* input_stream, int file_id, guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
int completion_id, int major_func, int minor_func); wStream* input_stream);
/** /**
* Handler for cleaning up the dynamically-allocated portions of a device. * 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, typedef void guac_rdpdr_device_free_handler(guac_rdp_common_svc* svc,
guac_rdpdr_device* device); guac_rdpdr_device* device);
@ -126,7 +184,30 @@ typedef struct guac_rdpdr {
/** /**
* Creates a new stream which contains the common 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. 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, wStream* guac_rdpdr_new_io_completion(guac_rdpdr_device* device,
int completion_id, int status, int size); int completion_id, int status, int size);