Merge pull request #49 from glyptodon/rdp-fs
GUAC-1172: Implement filesystem object support for RDP.
This commit is contained in:
commit
31e90bcdf4
@ -48,10 +48,10 @@ void guac_common_json_flush(guac_client* client, guac_stream* stream,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
int guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||||
guac_common_json_state* json_state, const char* buffer, int length) {
|
guac_common_json_state* json_state, const char* buffer, int length) {
|
||||||
|
|
||||||
bool blob_written = false;
|
int blob_written = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Append to and flush the JSON buffer as necessary to write the given
|
* Append to and flush the JSON buffer as necessary to write the given
|
||||||
@ -67,7 +67,7 @@ bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
|||||||
/* Flush if more room is needed */
|
/* Flush if more room is needed */
|
||||||
if (json_state->size + blob_length > sizeof(json_state->buffer)) {
|
if (json_state->size + blob_length > sizeof(json_state->buffer)) {
|
||||||
guac_common_json_flush(client, stream, json_state);
|
guac_common_json_flush(client, stream, json_state);
|
||||||
blob_written = true;
|
blob_written = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Append data to JSON buffer */
|
/* Append data to JSON buffer */
|
||||||
@ -86,11 +86,11 @@ bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool guac_common_json_write_string(guac_client* client,
|
int guac_common_json_write_string(guac_client* client,
|
||||||
guac_stream* stream, guac_common_json_state* json_state,
|
guac_stream* stream, guac_common_json_state* json_state,
|
||||||
const char* str) {
|
const char* str) {
|
||||||
|
|
||||||
bool blob_written = false;
|
int blob_written = 0;
|
||||||
|
|
||||||
/* Write starting quote */
|
/* Write starting quote */
|
||||||
blob_written |= guac_common_json_write(client, stream,
|
blob_written |= guac_common_json_write(client, stream,
|
||||||
@ -132,11 +132,11 @@ bool guac_common_json_write_string(guac_client* client,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
int guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||||
guac_common_json_state* json_state, const char* name,
|
guac_common_json_state* json_state, const char* name,
|
||||||
const char* value) {
|
const char* value) {
|
||||||
|
|
||||||
bool blob_written = false;
|
int blob_written = 0;
|
||||||
|
|
||||||
/* Write leading comma if not first property */
|
/* Write leading comma if not first property */
|
||||||
if (json_state->properties_written != 0)
|
if (json_state->properties_written != 0)
|
||||||
@ -173,7 +173,7 @@ void guac_common_json_begin_object(guac_client* client, guac_stream* stream,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
int guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
||||||
guac_common_json_state* json_state) {
|
guac_common_json_state* json_state) {
|
||||||
|
|
||||||
/* Write final brace of JSON object */
|
/* Write final brace of JSON object */
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/stream.h>
|
#include <guacamole/stream.h>
|
||||||
|
|
||||||
@ -97,9 +95,9 @@ void guac_common_json_flush(guac_client* client, guac_stream* stream,
|
|||||||
* The number of bytes in the buffer.
|
* The number of bytes in the buffer.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* true if at least one blob was written, false otherwise.
|
* Non-zero if at least one blob was written, zero otherwise.
|
||||||
*/
|
*/
|
||||||
bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
int guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||||
guac_common_json_state* json_state, const char* buffer, int length);
|
guac_common_json_state* json_state, const char* buffer, int length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,9 +121,9 @@ bool guac_common_json_write(guac_client* client, guac_stream* stream,
|
|||||||
* The string to write.
|
* The string to write.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* true if at least one blob was written, false otherwise.
|
* Non-zero if at least one blob was written, zero otherwise.
|
||||||
*/
|
*/
|
||||||
bool guac_common_json_write_string(guac_client* client,
|
int guac_common_json_write_string(guac_client* client,
|
||||||
guac_stream* stream, guac_common_json_state* json_state,
|
guac_stream* stream, guac_common_json_state* json_state,
|
||||||
const char* str);
|
const char* str);
|
||||||
|
|
||||||
@ -152,9 +150,9 @@ bool guac_common_json_write_string(guac_client* client,
|
|||||||
* The value of the property to write.
|
* The value of the property to write.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* true if at least one blob was written, false otherwise.
|
* Non-zero if at least one blob was written, zero otherwise.
|
||||||
*/
|
*/
|
||||||
bool guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
int guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||||
guac_common_json_state* json_state, const char* name,
|
guac_common_json_state* json_state, const char* name,
|
||||||
const char* value);
|
const char* value);
|
||||||
|
|
||||||
@ -192,9 +190,9 @@ void guac_common_json_begin_object(guac_client* client, guac_stream* stream,
|
|||||||
* The state object whose in-progress JSON object should be terminated.
|
* The state object whose in-progress JSON object should be terminated.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* true if at least one blob was written, false otherwise.
|
* Non-zero if at least one blob was written, zero otherwise.
|
||||||
*/
|
*/
|
||||||
bool guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
int guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
||||||
guac_common_json_state* json_state);
|
guac_common_json_state* json_state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
#include <freerdp/utils/svc_plugin.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/protocol.h>
|
||||||
|
#include <guacamole/socket.h>
|
||||||
|
|
||||||
#ifdef ENABLE_WINPR
|
#ifdef ENABLE_WINPR
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
@ -152,5 +154,10 @@ void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr) {
|
|||||||
/* Init data */
|
/* Init data */
|
||||||
device->data = data->filesystem;
|
device->data = data->filesystem;
|
||||||
|
|
||||||
|
/* Announce filesystem to client */
|
||||||
|
guac_protocol_send_filesystem(rdpdr->client->socket,
|
||||||
|
data->filesystem->object, "Shared Drive");
|
||||||
|
guac_socket_flush(rdpdr->client->socket);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "rdp_fs.h"
|
#include "rdp_fs.h"
|
||||||
#include "rdp_status.h"
|
#include "rdp_status.h"
|
||||||
|
#include "rdp_stream.h"
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -36,6 +37,7 @@
|
|||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <guacamole/object.h>
|
||||||
#include <guacamole/pool.h>
|
#include <guacamole/pool.h>
|
||||||
|
|
||||||
guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path) {
|
guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path) {
|
||||||
@ -43,6 +45,10 @@ guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path) {
|
|||||||
guac_rdp_fs* fs = malloc(sizeof(guac_rdp_fs));
|
guac_rdp_fs* fs = malloc(sizeof(guac_rdp_fs));
|
||||||
|
|
||||||
fs->client = client;
|
fs->client = client;
|
||||||
|
fs->object = guac_client_alloc_object(client);
|
||||||
|
fs->object->get_handler = guac_rdp_download_get_handler;
|
||||||
|
fs->object->put_handler = guac_rdp_upload_put_handler;
|
||||||
|
|
||||||
fs->drive_path = strdup(drive_path);
|
fs->drive_path = strdup(drive_path);
|
||||||
fs->file_id_pool = guac_pool_alloc(0);
|
fs->file_id_pool = guac_pool_alloc(0);
|
||||||
fs->open_files = 0;
|
fs->open_files = 0;
|
||||||
@ -52,6 +58,7 @@ guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void guac_rdp_fs_free(guac_rdp_fs* fs) {
|
void guac_rdp_fs_free(guac_rdp_fs* fs) {
|
||||||
|
guac_client_free_object(fs->client, fs->object);
|
||||||
guac_pool_free(fs->file_id_pool);
|
guac_pool_free(fs->file_id_pool);
|
||||||
free(fs->drive_path);
|
free(fs->drive_path);
|
||||||
free(fs);
|
free(fs);
|
||||||
@ -176,7 +183,7 @@ int guac_rdp_fs_open(guac_rdp_fs* fs, const char* path,
|
|||||||
path = "\\";
|
path = "\\";
|
||||||
|
|
||||||
/* If path is relative, the file does not exist */
|
/* If path is relative, the file does not exist */
|
||||||
else if (path[0] != '\\') {
|
else if (path[0] != '\\' && path[0] != '/') {
|
||||||
guac_client_log(fs->client, GUAC_LOG_DEBUG,
|
guac_client_log(fs->client, GUAC_LOG_DEBUG,
|
||||||
"%s: Access denied - supplied path \"%s\" is relative.",
|
"%s: Access denied - supplied path \"%s\" is relative.",
|
||||||
__func__, path);
|
__func__, path);
|
||||||
@ -688,3 +695,65 @@ int guac_rdp_fs_get_info(guac_rdp_fs* fs, guac_rdp_fs_info* info) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_rdp_fs_append_filename(char* fullpath, const char* path,
|
||||||
|
const char* filename) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Disallow "." as a filename */
|
||||||
|
if (strcmp(filename, ".") == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Disallow ".." as a filename */
|
||||||
|
if (strcmp(filename, "..") == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Copy path, append trailing slash */
|
||||||
|
for (i=0; i<GUAC_RDP_FS_MAX_PATH; i++) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append trailing slash only if:
|
||||||
|
* 1) Trailing slash is not already present
|
||||||
|
* 2) Path is non-empty
|
||||||
|
*/
|
||||||
|
|
||||||
|
char c = path[i];
|
||||||
|
if (c == '\0') {
|
||||||
|
if (i > 0 && path[i-1] != '/' && path[i-1] != '\\')
|
||||||
|
fullpath[i++] = '/';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy character if not end of string */
|
||||||
|
fullpath[i] = c;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append filename */
|
||||||
|
for (; i<GUAC_RDP_FS_MAX_PATH; i++) {
|
||||||
|
|
||||||
|
char c = *(filename++);
|
||||||
|
if (c == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Filenames may not contain slashes */
|
||||||
|
if (c == '\\' || c == '/')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Append each character within filename */
|
||||||
|
fullpath[i] = c;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify path length is within maximum */
|
||||||
|
if (i == GUAC_RDP_FS_MAX_PATH)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Terminate path string */
|
||||||
|
fullpath[i] = '\0';
|
||||||
|
|
||||||
|
/* Append was successful */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/object.h>
|
||||||
#include <guacamole/pool.h>
|
#include <guacamole/pool.h>
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
@ -272,6 +273,11 @@ typedef struct guac_rdp_fs {
|
|||||||
*/
|
*/
|
||||||
guac_client* client;
|
guac_client* client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlying filesystem object.
|
||||||
|
*/
|
||||||
|
guac_object* object;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root of the filesystem.
|
* The root of the filesystem.
|
||||||
*/
|
*/
|
||||||
@ -422,5 +428,27 @@ int guac_rdp_fs_matches(const char* filename, const char* pattern);
|
|||||||
*/
|
*/
|
||||||
int guac_rdp_fs_get_info(guac_rdp_fs* fs, guac_rdp_fs_info* info);
|
int guac_rdp_fs_get_info(guac_rdp_fs* fs, guac_rdp_fs_info* info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenates the given filename with the given path, separating the two
|
||||||
|
* with a single forward slash. The full result must be no more than
|
||||||
|
* GUAC_RDP_FS_MAX_PATH bytes long, counting null terminator.
|
||||||
|
*
|
||||||
|
* @param fullpath
|
||||||
|
* The buffer to store the result within. This buffer must be at least
|
||||||
|
* GUAC_RDP_FS_MAX_PATH bytes long.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path to append the filename to.
|
||||||
|
*
|
||||||
|
* @param filename
|
||||||
|
* The filename to append to the path.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Non-zero if the filename is valid and was successfully appended to the
|
||||||
|
* path, zero otherwise.
|
||||||
|
*/
|
||||||
|
int guac_rdp_fs_append_filename(char* fullpath, const char* path,
|
||||||
|
const char* filename);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -32,6 +32,14 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
/* Include any constants from winpr/file.h, if available */
|
||||||
|
|
||||||
|
#ifdef ENABLE_WINPR
|
||||||
|
#include <winpr/file.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Constants which MAY be defined within FreeRDP */
|
||||||
|
|
||||||
#ifndef STATUS_SUCCESS
|
#ifndef STATUS_SUCCESS
|
||||||
#define STATUS_SUCCESS 0x00000000
|
#define STATUS_SUCCESS 0x00000000
|
||||||
#define STATUS_NO_MORE_FILES 0x80000006
|
#define STATUS_NO_MORE_FILES 0x80000006
|
||||||
@ -53,7 +61,9 @@
|
|||||||
#define STATUS_FILE_CLOSED 0xC0000128
|
#define STATUS_FILE_CLOSED 0xC0000128
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Constants which are NEVER defined within FreeRDP */
|
||||||
|
|
||||||
#define STATUS_FILE_SYSTEM_LIMITATION 0xC0000427
|
#define STATUS_FILE_SYSTEM_LIMITATION 0xC0000427
|
||||||
#define STATUS_FILE_TOO_LARGE 0xC0000904
|
#define STATUS_FILE_TOO_LARGE 0xC0000904
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -356,4 +356,216 @@ int guac_rdp_download_ack_handler(guac_client* client, guac_stream* stream,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_rdp_ls_ack_handler(guac_client* client, guac_stream* stream,
|
||||||
|
char* message, guac_protocol_status status) {
|
||||||
|
|
||||||
|
int blob_written = 0;
|
||||||
|
const char* filename;
|
||||||
|
|
||||||
|
guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;
|
||||||
|
|
||||||
|
/* If unsuccessful, free stream and abort */
|
||||||
|
if (status != GUAC_PROTOCOL_STATUS_SUCCESS) {
|
||||||
|
guac_rdp_fs_close(rdp_stream->ls_status.fs,
|
||||||
|
rdp_stream->ls_status.file_id);
|
||||||
|
guac_client_free_stream(client, stream);
|
||||||
|
free(rdp_stream);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* While directory entries remain */
|
||||||
|
while ((filename = guac_rdp_fs_read_dir(rdp_stream->ls_status.fs,
|
||||||
|
rdp_stream->ls_status.file_id)) != NULL
|
||||||
|
&& !blob_written) {
|
||||||
|
|
||||||
|
char absolute_path[GUAC_RDP_FS_MAX_PATH];
|
||||||
|
|
||||||
|
/* Skip current and parent directory entries */
|
||||||
|
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Concatenate into absolute path - skip if invalid */
|
||||||
|
if (!guac_rdp_fs_append_filename(absolute_path,
|
||||||
|
rdp_stream->ls_status.directory_name, filename)) {
|
||||||
|
|
||||||
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
|
"Skipping filename \"%s\" - filename is invalid or "
|
||||||
|
"resulting path is too long", filename);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt to open file to determine type */
|
||||||
|
int file_id = guac_rdp_fs_open(rdp_stream->ls_status.fs, absolute_path,
|
||||||
|
ACCESS_GENERIC_READ, 0, DISP_FILE_OPEN, 0);
|
||||||
|
if (file_id < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Get opened file */
|
||||||
|
guac_rdp_fs_file* file = guac_rdp_fs_get_file(rdp_stream->ls_status.fs,
|
||||||
|
file_id);
|
||||||
|
if (file == NULL) {
|
||||||
|
guac_client_log(rdp_stream->ls_status.fs->client, GUAC_LOG_DEBUG,
|
||||||
|
"%s: Successful open produced bad file_id: %i",
|
||||||
|
__func__, file_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine mimetype */
|
||||||
|
const char* mimetype;
|
||||||
|
if (file->attributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
mimetype = GUAC_CLIENT_STREAM_INDEX_MIMETYPE;
|
||||||
|
else
|
||||||
|
mimetype = "application/octet-stream";
|
||||||
|
|
||||||
|
/* Write entry */
|
||||||
|
blob_written |= guac_common_json_write_property(client, stream,
|
||||||
|
&rdp_stream->ls_status.json_state, absolute_path, mimetype);
|
||||||
|
|
||||||
|
guac_rdp_fs_close(rdp_stream->ls_status.fs, file_id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complete JSON and cleanup at end of directory */
|
||||||
|
if (filename == NULL) {
|
||||||
|
|
||||||
|
/* Complete JSON object */
|
||||||
|
guac_common_json_end_object(client, stream,
|
||||||
|
&rdp_stream->ls_status.json_state);
|
||||||
|
guac_common_json_flush(client, stream,
|
||||||
|
&rdp_stream->ls_status.json_state);
|
||||||
|
|
||||||
|
/* Clean up resources */
|
||||||
|
guac_rdp_fs_close(rdp_stream->ls_status.fs,
|
||||||
|
rdp_stream->ls_status.file_id);
|
||||||
|
free(rdp_stream);
|
||||||
|
|
||||||
|
/* Signal of stream */
|
||||||
|
guac_protocol_send_end(client->socket, stream);
|
||||||
|
guac_client_free_stream(client, stream);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
guac_socket_flush(client->socket);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_rdp_download_get_handler(guac_client* client, guac_object* object,
|
||||||
|
char* name) {
|
||||||
|
|
||||||
|
/* Get filesystem, ignore request if no filesystem */
|
||||||
|
guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
|
||||||
|
if (fs == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Attempt to open file for reading */
|
||||||
|
int file_id = guac_rdp_fs_open(fs, name, ACCESS_GENERIC_READ, 0,
|
||||||
|
DISP_FILE_OPEN, 0);
|
||||||
|
if (file_id < 0) {
|
||||||
|
guac_client_log(client, GUAC_LOG_INFO, "Unable to read file \"%s\"",
|
||||||
|
name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get opened file */
|
||||||
|
guac_rdp_fs_file* file = guac_rdp_fs_get_file(fs, file_id);
|
||||||
|
if (file == NULL) {
|
||||||
|
guac_client_log(fs->client, GUAC_LOG_DEBUG,
|
||||||
|
"%s: Successful open produced bad file_id: %i",
|
||||||
|
__func__, file_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If directory, send contents of directory */
|
||||||
|
if (file->attributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
|
|
||||||
|
/* Create stream data */
|
||||||
|
guac_rdp_stream* rdp_stream = malloc(sizeof(guac_rdp_stream));
|
||||||
|
rdp_stream->type = GUAC_RDP_LS_STREAM;
|
||||||
|
rdp_stream->ls_status.fs = fs;
|
||||||
|
rdp_stream->ls_status.file_id = file_id;
|
||||||
|
strncpy(rdp_stream->ls_status.directory_name, name,
|
||||||
|
sizeof(rdp_stream->ls_status.directory_name));
|
||||||
|
|
||||||
|
/* Allocate stream for body */
|
||||||
|
guac_stream* stream = guac_client_alloc_stream(client);
|
||||||
|
stream->ack_handler = guac_rdp_ls_ack_handler;
|
||||||
|
stream->data = rdp_stream;
|
||||||
|
|
||||||
|
/* Init JSON object state */
|
||||||
|
guac_common_json_begin_object(client, stream,
|
||||||
|
&rdp_stream->ls_status.json_state);
|
||||||
|
|
||||||
|
/* Associate new stream with get request */
|
||||||
|
guac_protocol_send_body(client->socket, object, stream,
|
||||||
|
GUAC_CLIENT_STREAM_INDEX_MIMETYPE, name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, send file contents */
|
||||||
|
else {
|
||||||
|
|
||||||
|
/* Create stream data */
|
||||||
|
guac_rdp_stream* rdp_stream = malloc(sizeof(guac_rdp_stream));
|
||||||
|
rdp_stream->type = GUAC_RDP_DOWNLOAD_STREAM;
|
||||||
|
rdp_stream->download_status.file_id = file_id;
|
||||||
|
rdp_stream->download_status.offset = 0;
|
||||||
|
|
||||||
|
/* Allocate stream for body */
|
||||||
|
guac_stream* stream = guac_client_alloc_stream(client);
|
||||||
|
stream->data = rdp_stream;
|
||||||
|
stream->ack_handler = guac_rdp_download_ack_handler;
|
||||||
|
|
||||||
|
/* Associate new stream with get request */
|
||||||
|
guac_protocol_send_body(client->socket, object, stream,
|
||||||
|
"application/octet-stream", name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
guac_socket_flush(client->socket);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_rdp_upload_put_handler(guac_client* client, guac_object* object,
|
||||||
|
guac_stream* stream, char* mimetype, char* name) {
|
||||||
|
|
||||||
|
/* 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_SERVER_ERROR);
|
||||||
|
guac_socket_flush(client->socket);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open file */
|
||||||
|
int file_id = guac_rdp_fs_open(fs, name, ACCESS_GENERIC_WRITE, 0,
|
||||||
|
DISP_FILE_OVERWRITE_IF, 0);
|
||||||
|
|
||||||
|
/* Abort on failure */
|
||||||
|
if (file_id < 0) {
|
||||||
|
guac_protocol_send_ack(client->socket, stream, "FAIL (CANNOT OPEN)",
|
||||||
|
GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
|
||||||
|
guac_socket_flush(client->socket);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init upload stream data */
|
||||||
|
guac_rdp_stream* rdp_stream = malloc(sizeof(guac_rdp_stream));
|
||||||
|
rdp_stream->type = GUAC_RDP_UPLOAD_STREAM;
|
||||||
|
rdp_stream->upload_status.offset = 0;
|
||||||
|
rdp_stream->upload_status.file_id = file_id;
|
||||||
|
|
||||||
|
/* Allocate stream, init for file upload */
|
||||||
|
stream->data = rdp_stream;
|
||||||
|
stream->blob_handler = guac_rdp_upload_blob_handler;
|
||||||
|
stream->end_handler = guac_rdp_upload_end_handler;
|
||||||
|
|
||||||
|
/* Acknowledge stream creation */
|
||||||
|
guac_protocol_send_ack(client->socket, stream, "OK (STREAM BEGIN)",
|
||||||
|
GUAC_PROTOCOL_STATUS_SUCCESS);
|
||||||
|
guac_socket_flush(client->socket);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#define _GUAC_RDP_STREAM_H
|
#define _GUAC_RDP_STREAM_H
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "guac_json.h"
|
||||||
#include "rdp_svc.h"
|
#include "rdp_svc.h"
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
@ -68,6 +69,33 @@ typedef struct guac_rdp_upload_status {
|
|||||||
|
|
||||||
} guac_rdp_upload_status;
|
} guac_rdp_upload_status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current state of a directory listing operation.
|
||||||
|
*/
|
||||||
|
typedef struct guac_rdp_ls_status {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The filesystem associated with the directory being listed.
|
||||||
|
*/
|
||||||
|
guac_rdp_fs* fs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file ID of the directory being listed.
|
||||||
|
*/
|
||||||
|
int file_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The absolute path of the directory being listed.
|
||||||
|
*/
|
||||||
|
char directory_name[GUAC_RDP_FS_MAX_PATH];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current state of the JSON directory object being written.
|
||||||
|
*/
|
||||||
|
guac_common_json_state json_state;
|
||||||
|
|
||||||
|
} guac_rdp_ls_status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All available stream types.
|
* All available stream types.
|
||||||
*/
|
*/
|
||||||
@ -83,6 +111,11 @@ typedef enum guac_rdp_stream_type {
|
|||||||
*/
|
*/
|
||||||
GUAC_RDP_DOWNLOAD_STREAM,
|
GUAC_RDP_DOWNLOAD_STREAM,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An in-progress stream of a directory listing.
|
||||||
|
*/
|
||||||
|
GUAC_RDP_LS_STREAM,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The inbound half of a static virtual channel.
|
* The inbound half of a static virtual channel.
|
||||||
*/
|
*/
|
||||||
@ -115,6 +148,11 @@ typedef struct guac_rdp_stream {
|
|||||||
*/
|
*/
|
||||||
guac_rdp_download_status download_status;
|
guac_rdp_download_status download_status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directory list status. Only valid for GUAC_RDP_LS_STREAM.
|
||||||
|
*/
|
||||||
|
guac_rdp_ls_status ls_status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associated SVC instance. Only valid for GUAC_RDP_INBOUND_SVC_STREAM.
|
* Associated SVC instance. Only valid for GUAC_RDP_INBOUND_SVC_STREAM.
|
||||||
*/
|
*/
|
||||||
@ -174,5 +212,76 @@ int guac_rdp_clipboard_end_handler(guac_client* client, guac_stream* stream);
|
|||||||
int guac_rdp_download_ack_handler(guac_client* client, guac_stream* stream,
|
int guac_rdp_download_ack_handler(guac_client* client, guac_stream* stream,
|
||||||
char* message, guac_protocol_status status);
|
char* message, guac_protocol_status status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for ack messages received due to receipt of a "body" or "blob"
|
||||||
|
* instruction associated with a directory list operation.
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The client receiving the ack message.
|
||||||
|
*
|
||||||
|
* @param stream
|
||||||
|
* The Guacamole protocol stream associated with the received ack message.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* An arbitrary human-readable message describing the nature of the
|
||||||
|
* success or failure denoted by this ack message.
|
||||||
|
*
|
||||||
|
* @param status
|
||||||
|
* The status code associated with this ack message, which may indicate
|
||||||
|
* success or an error.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on error.
|
||||||
|
*/
|
||||||
|
int guac_rdp_ls_ack_handler(guac_client* client, guac_stream* stream,
|
||||||
|
char* message, guac_protocol_status status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for get messages. In context of downloads and the filesystem exposed
|
||||||
|
* via the Guacamole protocol, get messages request the body of a file within
|
||||||
|
* the filesystem.
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The client receiving the get message.
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* The Guacamole protocol object associated with the get request itself.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the input stream (file) being requested.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on error.
|
||||||
|
*/
|
||||||
|
int guac_rdp_download_get_handler(guac_client* client, guac_object* object,
|
||||||
|
char* name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for put messages. In context of uploads and the filesystem exposed
|
||||||
|
* via the Guacamole protocol, put messages request write access to a file
|
||||||
|
* within the filesystem.
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The client receiving the put message.
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* The Guacamole protocol object associated with the put request itself.
|
||||||
|
*
|
||||||
|
* @param stream
|
||||||
|
* The Guacamole protocol stream along which the client will be sending
|
||||||
|
* file data.
|
||||||
|
*
|
||||||
|
* @param mimetype
|
||||||
|
* The mimetype of the data being send along the stream.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the input stream (file) being requested.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on error.
|
||||||
|
*/
|
||||||
|
int guac_rdp_upload_put_handler(guac_client* client, guac_object* object,
|
||||||
|
guac_stream* stream, char* mimetype, char* name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user