diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c index 37c360d7..e7089b6d 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c @@ -115,7 +115,6 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path, guac_rdpdr_fs_data* data = (guac_rdpdr_fs_data*) device->data; char real_path[GUAC_RDPDR_FS_MAX_PATH]; char normalized_path[GUAC_RDPDR_FS_MAX_PATH]; - char* filename; struct stat file_stat; int fd; @@ -213,13 +212,6 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path, file->dir = NULL; file->absolute_path = strdup(normalized_path); - /* Parse out filename */ - filename = file->absolute_path; - while (*filename != '\\' && *filename != '/' && *filename != 0) - filename++; - - file->name = filename; - /* Attempt to pull file information */ if (fstat(fd, &file_stat) == 0) { @@ -310,6 +302,10 @@ const char* guac_rdpdr_fs_read_dir(guac_rdpdr_device* device, int file_id) { if (readdir_r(file->dir, &(file->__dirent), &result)) return NULL; + /* If no more entries, return NULL */ + if (result == NULL) + return NULL; + /* Return filename */ return file->__dirent.d_name; diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h index 79f0de03..0f038831 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h @@ -143,12 +143,6 @@ */ typedef struct guac_rdpdr_fs_file { - /** - * The filename of this file. The data of this name is actually stored - * within the absolute_path. - */ - char* name; - /** * The absolute path, including filename, of this file. */ diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c index a057d1a4..4beb3161 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c @@ -275,6 +275,8 @@ void guac_rdpdr_fs_process_notify_change_directory(guac_rdpdr_device* device, void guac_rdpdr_fs_process_query_directory(guac_rdpdr_device* device, wStream* input_stream, int file_id, int completion_id) { + wStream* output_stream; + guac_rdpdr_fs_data* data = (guac_rdpdr_fs_data*) device->data; guac_rdpdr_fs_file* file = &(data->files[file_id]); int fs_information_class, initial_query; @@ -309,47 +311,75 @@ void guac_rdpdr_fs_process_query_directory(guac_rdpdr_device* device, wStream* i entry_name = guac_rdpdr_fs_read_dir(device, file_id); if (entry_name != NULL) { + int entry_file_id; + /* Convert to absolute path */ char entry_path[GUAC_RDPDR_FS_MAX_PATH]; if (guac_rdpdr_fs_convert_path(file->absolute_path, entry_name, entry_path)) - guac_client_log_info(device->rdpdr->client, "Conversion failed"); /* FIXME: Return ENOENT */ + guac_client_log_info(device->rdpdr->client, + "Conversion failed: parent=\"%s\", name=\"%s\"", + file->absolute_path, entry_name); /* FIXME: Return no-more-files */ - guac_client_log_info(device->rdpdr->client, "parent=\"%s\", name=\"%s\", path=\"%s\"", - file->absolute_path, entry_name, entry_path); + else { - /* Dispatch to appropriate class-specific handler */ - switch (fs_information_class) { + /* Open directory entry */ + entry_file_id = guac_rdpdr_fs_open(device, entry_path, + ACCESS_FILE_READ_DATA, DISP_FILE_OVERWRITE); - case FileDirectoryInformation: - guac_rdpdr_fs_process_query_directory_info(device, input_stream, - file_id, completion_id); - break; + if (entry_file_id >= 0) { - case FileFullDirectoryInformation: - guac_rdpdr_fs_process_query_full_directory_info(device, input_stream, - file_id, completion_id); - break; + /* Dispatch to appropriate class-specific handler */ + switch (fs_information_class) { - case FileBothDirectoryInformation: - guac_rdpdr_fs_process_query_both_directory_info(device, input_stream, - file_id, completion_id); - break; + case FileDirectoryInformation: + guac_rdpdr_fs_process_query_directory_info(device, + entry_name, entry_file_id, completion_id); + break; - case FileNamesInformation: - guac_rdpdr_fs_process_query_names_info(device, input_stream, - file_id, completion_id); - break; + case FileFullDirectoryInformation: + guac_rdpdr_fs_process_query_full_directory_info(device, + entry_name, entry_file_id, completion_id); + break; - default: - guac_client_log_info(device->rdpdr->client, - "Unknown dir information class: 0x%x", fs_information_class); - } + case FileBothDirectoryInformation: + guac_rdpdr_fs_process_query_both_directory_info(device, + entry_name, entry_file_id, completion_id); + break; - } + case FileNamesInformation: + guac_rdpdr_fs_process_query_names_info(device, + entry_name, entry_file_id, completion_id); + break; - /* Otherwise, send STATUS_NO_MORE_FILES */ - else { - } + default: + guac_client_log_info(device->rdpdr->client, + "Unknown dir information class: 0x%x", fs_information_class); + } + + guac_rdpdr_fs_close(device, entry_file_id); + return; + + } /* end if file exists */ + } /* end if path valid */ + } /* end if entry exists */ + + /* + * Handle errors as a lack of files. + */ + + output_stream = Stream_New(NULL, 16); + + /* Write header */ + Stream_Write_UINT16(output_stream, RDPDR_CTYP_CORE); + Stream_Write_UINT16(output_stream, PAKID_CORE_DEVICE_IOCOMPLETION); + + /* Write content */ + Stream_Write_UINT32(output_stream, device->device_id); + Stream_Write_UINT32(output_stream, completion_id); + Stream_Write_UINT32(output_stream, STATUS_NO_MORE_FILES); + + svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream); + guac_client_log_info(device->rdpdr->client, "Sent STATUS_NO_MORE_FILES"); } diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_dir_info.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_dir_info.c index b8a22acc..203c1cf0 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_dir_info.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_dir_info.c @@ -41,28 +41,78 @@ #include "compat/winpr-stream.h" #endif +#include + #include "rdpdr_service.h" +#include "rdpdr_messages.h" +#include "rdpdr_fs.h" +#include "unicode.h" void guac_rdpdr_fs_process_query_directory_info(guac_rdpdr_device* device, - wStream* input_stream, int file_id, int completion_id) { + const char* entry_name, int file_id, int completion_id) { /* STUB */ guac_client_log_info(device->rdpdr->client, "STUB: %s", __func__); } void guac_rdpdr_fs_process_query_full_directory_info(guac_rdpdr_device* device, - wStream* input_stream, int file_id, int completion_id) { + const char* entry_name, int file_id, int completion_id) { /* STUB */ guac_client_log_info(device->rdpdr->client, "STUB: %s", __func__); } void guac_rdpdr_fs_process_query_both_directory_info(guac_rdpdr_device* device, - wStream* input_stream, int file_id, int completion_id) { - /* STUB */ - guac_client_log_info(device->rdpdr->client, "STUB: %s", __func__); + const char* entry_name, int file_id, int completion_id) { + + guac_rdpdr_fs_data* data = (guac_rdpdr_fs_data*) device->data; + guac_rdpdr_fs_file* file = &(data->files[file_id]); + + wStream* output_stream = Stream_New(NULL, 256); + int length = guac_utf8_strlen(entry_name); + int utf16_length = length*2; + + unsigned char utf16_entry_name[256]; + guac_rdp_utf8_to_utf16((const unsigned char*) entry_name, (char*) utf16_entry_name, length); + + /* Write header */ + Stream_Write_UINT16(output_stream, RDPDR_CTYP_CORE); + Stream_Write_UINT16(output_stream, PAKID_CORE_DEVICE_IOCOMPLETION); + + /* Write content */ + Stream_Write_UINT32(output_stream, device->device_id); + Stream_Write_UINT32(output_stream, completion_id); + Stream_Write_UINT32(output_stream, STATUS_SUCCESS); + + Stream_Write_UINT32(output_stream, + 69 + 24 + utf16_length); /* Length */ + + Stream_Write_UINT32(output_stream, 0); /* NextEntryOffset */ + Stream_Write_UINT32(output_stream, 0); /* FileIndex */ + Stream_Write_UINT64(output_stream, file->ctime); /* CreationTime */ + Stream_Write_UINT64(output_stream, file->atime); /* LastAccessTime */ + Stream_Write_UINT64(output_stream, file->mtime); /* LastWriteTime */ + Stream_Write_UINT64(output_stream, file->mtime); /* ChangeTime */ + Stream_Write_UINT64(output_stream, file->size); /* EndOfFile */ + Stream_Write_UINT64(output_stream, file->size); /* AllocationSize */ + Stream_Write_UINT32(output_stream, file->attributes); /* FileAttributes */ + Stream_Write_UINT32(output_stream, utf16_length); /* FileNameLength*/ + Stream_Write_UINT32(output_stream, 0); /* EaSize */ + Stream_Write_UINT8(output_stream, 0); /* ShortNameLength */ + + /* Apparently, the reserved byte here must be skipped ... */ + + Stream_Seek(output_stream, 24); /* ShortName */ + Stream_Write(output_stream, utf16_entry_name, utf16_length); /* FileName */ + + svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream); + guac_client_log_info(device->rdpdr->client, "Sent directory entry: \"%s\"", + entry_name); + guac_client_log_info(device->rdpdr->client, "Attrib: 0x%x", file->attributes); + guac_client_log_info(device->rdpdr->client, "Size: %i", file->size); + } void guac_rdpdr_fs_process_query_names_info(guac_rdpdr_device* device, - wStream* input_stream, int file_id, int completion_id) { + const char* entry_name, int file_id, int completion_id) { /* STUB */ guac_client_log_info(device->rdpdr->client, "STUB: %s", __func__); } diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_dir_info.h b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_dir_info.h index cef128c4..c6bfddc8 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_dir_info.h +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_dir_info.h @@ -60,7 +60,7 @@ * attributes." */ void guac_rdpdr_fs_process_query_directory_info(guac_rdpdr_device* device, - wStream* input_stream, int file_id, int completion_id); + const char* entry_name, int file_id, int completion_id); /** * Processes a query request for FileFullDirectoryInformation. From the @@ -68,7 +68,7 @@ void guac_rdpdr_fs_process_query_directory_info(guac_rdpdr_device* device, * attribute size." */ void guac_rdpdr_fs_process_query_full_directory_info(guac_rdpdr_device* device, - wStream* input_stream, int file_id, int completion_id); + const char* entry_name, int file_id, int completion_id); /** * Processes a query request for FileBothDirectoryInformation. From the @@ -76,14 +76,14 @@ void guac_rdpdr_fs_process_query_full_directory_info(guac_rdpdr_device* device, * extended attribute size and short name about a file or directory." */ void guac_rdpdr_fs_process_query_both_directory_info(guac_rdpdr_device* device, - wStream* input_stream, int file_id, int completion_id); + const char* entry_name, int file_id, int completion_id); /** * 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_rdpdr_device* device, - wStream* input_stream, int file_id, int completion_id); + const char* entry_name, int file_id, int completion_id); #endif