diff --git a/src/protocols/rdp/guac_handlers.c b/src/protocols/rdp/guac_handlers.c index 20583a7c..09baabbe 100644 --- a/src/protocols/rdp/guac_handlers.c +++ b/src/protocols/rdp/guac_handlers.c @@ -495,10 +495,72 @@ int rdp_guac_client_clipboard_handler(guac_client* client, char* data) { } +/** + * Writes the given filename to the given upload path, sanitizing the filename + * and translating the filename to the root directory. + */ +static void __generate_upload_path(const char* filename, char* path) { + + int i; + + /* Add initial backslash */ + *(path++) = '\\'; + + for (i=1; iindex, filename, mimetype); + + int file_id; + guac_rdp_upload_stat* stat; + char file_path[GUAC_RDP_FS_MAX_PATH]; + + /* Get filesystem, return error if no filesystem */ + guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem; + if (fs == NULL) { + guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)", + GUAC_PROTOCOL_STATUS_INTERNAL_ERROR); + guac_socket_flush(client->socket); + return 0; + } + + /* Translate name */ + __generate_upload_path(filename, file_path); + + /* Open file */ + file_id = guac_rdp_fs_open(fs, file_path, ACCESS_GENERIC_WRITE, 0, + DISP_FILE_OVERWRITE_IF, 0); + if (file_id < 0) { + guac_protocol_send_ack(client->socket, stream, "FAIL (CANNOT OPEN)", + GUAC_PROTOCOL_STATUS_PERMISSION_DENIED); + guac_socket_flush(client->socket); + return 0; + } + + /* Init upload status */ + stat = malloc(sizeof(guac_rdp_upload_stat)); + stat->offset = 0; + stat->file_id = file_id; + stream->data = stat; + guac_protocol_send_ack(client->socket, stream, "OK (STREAM BEGIN)", GUAC_PROTOCOL_STATUS_SUCCESS); guac_socket_flush(client->socket); @@ -507,7 +569,44 @@ int rdp_guac_client_file_handler(guac_client* client, guac_stream* stream, int rdp_guac_client_blob_handler(guac_client* client, guac_stream* stream, void* data, int length) { - /* STUB */ + + int bytes_written; + guac_rdp_upload_stat* stat; + + /* Get filesystem, return error if no filesystem */ + guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem; + if (fs == NULL) { + guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)", + GUAC_PROTOCOL_STATUS_INTERNAL_ERROR); + guac_socket_flush(client->socket); + return 0; + } + + /* Get upload status */ + stat = (guac_rdp_upload_stat*) stream->data; + + /* Write entire block */ + while (length > 0) { + + /* Attempt write */ + bytes_written = guac_rdp_fs_write(fs, stat->file_id, stat->offset, + data, length); + + /* On error, abort */ + if (bytes_written < 0) { + guac_protocol_send_ack(client->socket, stream, "FAIL (BAD WRITE)", + GUAC_PROTOCOL_STATUS_PERMISSION_DENIED); + guac_socket_flush(client->socket); + return 0; + } + + /* Update counters */ + stat->offset += bytes_written; + data += bytes_written; + length -= bytes_written; + + } + guac_protocol_send_ack(client->socket, stream, "OK (DATA WRITTEN)", GUAC_PROTOCOL_STATUS_SUCCESS); guac_socket_flush(client->socket); @@ -515,8 +614,25 @@ int rdp_guac_client_blob_handler(guac_client* client, guac_stream* stream, } int rdp_guac_client_end_handler(guac_client* client, guac_stream* stream) { - guac_client_log_info(client, "STUB: stream %i closed", - stream->index); + + guac_rdp_upload_stat* stat; + + /* Get filesystem, return error if no filesystem */ + guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem; + if (fs == NULL) { + guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)", + GUAC_PROTOCOL_STATUS_INTERNAL_ERROR); + guac_socket_flush(client->socket); + return 0; + } + + /* Get upload status */ + stat = (guac_rdp_upload_stat*) stream->data; + + /* Close file */ + guac_rdp_fs_close(fs, stat->file_id); + free(stat); + guac_protocol_send_ack(client->socket, stream, "OK (STREAM END)", GUAC_PROTOCOL_STATUS_SUCCESS); guac_socket_flush(client->socket); diff --git a/src/protocols/rdp/guac_handlers.h b/src/protocols/rdp/guac_handlers.h index 58c3dbe0..d37c7f23 100644 --- a/src/protocols/rdp/guac_handlers.h +++ b/src/protocols/rdp/guac_handlers.h @@ -41,6 +41,24 @@ #include #include +/** + * Structure which represents the current state of an upload. + */ +typedef struct guac_rdp_upload_stat { + + /** + * The overall offset within the file that the next write should + * occur at. + */ + int offset; + + /** + * The ID of the file being written to. + */ + int file_id; + +} guac_rdp_upload_stat; + int rdp_guac_client_free_handler(guac_client* client); int rdp_guac_client_handle_messages(guac_client* client); int rdp_guac_client_mouse_handler(guac_client* client, int x, int y, int mask); diff --git a/src/protocols/rdp/rdp_fs.c b/src/protocols/rdp/rdp_fs.c index ead8b355..cb99915b 100644 --- a/src/protocols/rdp/rdp_fs.c +++ b/src/protocols/rdp/rdp_fs.c @@ -283,6 +283,7 @@ int guac_rdp_fs_open(guac_rdp_fs* fs, const char* path, /* Get file ID, init file */ file_id = guac_pool_next_int(fs->file_id_pool); file = &(fs->files[file_id]); + file->id = file_id; file->fd = fd; file->dir = NULL; file->dir_pattern[0] = '\0'; diff --git a/src/protocols/rdp/rdp_fs.h b/src/protocols/rdp/rdp_fs.h index 3e697add..274d183e 100644 --- a/src/protocols/rdp/rdp_fs.h +++ b/src/protocols/rdp/rdp_fs.h @@ -191,6 +191,11 @@ */ typedef struct guac_rdp_fs_file { + /** + * The ID of this file. + */ + int id; + /** * The absolute path, including filename, of this file. */