Add path normalization.
This commit is contained in:
parent
52f9bac805
commit
69d636860d
@ -61,11 +61,12 @@
|
|||||||
#include <freerdp/utils/svc_plugin.h>
|
#include <freerdp/utils/svc_plugin.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates an absolute Windows path to an absolute path which is within the "drive path"
|
* Translates an absolute Windows virtual_path to an absolute virtual_path
|
||||||
* specified in the connection settings.
|
* which is within the "drive virtual_path" specified in the connection
|
||||||
|
* settings.
|
||||||
*/
|
*/
|
||||||
static char* __guac_rdpdr_fs_translate_path(guac_rdpdr_device* device,
|
static void __guac_rdpdr_fs_translate_path(guac_rdpdr_device* device,
|
||||||
const char* path, char* path_buffer) {
|
const char* virtual_path, char* real_path) {
|
||||||
|
|
||||||
/* Get drive path */
|
/* Get drive path */
|
||||||
rdp_guac_client_data* client_data = (rdp_guac_client_data*) device->rdpdr->client->data;
|
rdp_guac_client_data* client_data = (rdp_guac_client_data*) device->rdpdr->client->data;
|
||||||
@ -82,7 +83,7 @@ static char* __guac_rdpdr_fs_translate_path(guac_rdpdr_device* device,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Copy character */
|
/* Copy character */
|
||||||
*(path_buffer++) = c;
|
*(real_path++) = c;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,29 +91,21 @@ static char* __guac_rdpdr_fs_translate_path(guac_rdpdr_device* device,
|
|||||||
for (; i<GUAC_RDPDR_FS_MAX_PATH-1; i++) {
|
for (; i<GUAC_RDPDR_FS_MAX_PATH-1; i++) {
|
||||||
|
|
||||||
/* Stop at end of string */
|
/* Stop at end of string */
|
||||||
char c = *path;
|
char c = *(virtual_path++);
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Disallow ".." */
|
|
||||||
if (c == '.' && *(path-1) == '.')
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Translate backslashes to forward slashes */
|
/* Translate backslashes to forward slashes */
|
||||||
if (c == '\\')
|
if (c == '\\')
|
||||||
c = '/';
|
c = '/';
|
||||||
|
|
||||||
/* Store in real path buffer */
|
/* Store in real path buffer */
|
||||||
*(path_buffer++)= c;
|
*(real_path++)= c;
|
||||||
|
|
||||||
/* Next path character */
|
|
||||||
path++;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Null terminator */
|
/* Null terminator */
|
||||||
*(path_buffer++)= 0;
|
*real_path = 0;
|
||||||
return path_buffer;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +113,8 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path,
|
|||||||
int access, int create_disposition) {
|
int access, int create_disposition) {
|
||||||
|
|
||||||
guac_rdpdr_fs_data* data = (guac_rdpdr_fs_data*) device->data;
|
guac_rdpdr_fs_data* data = (guac_rdpdr_fs_data*) device->data;
|
||||||
char path_buffer[GUAC_RDPDR_FS_MAX_PATH];
|
char real_path[GUAC_RDPDR_FS_MAX_PATH];
|
||||||
|
char normalized_path[GUAC_RDPDR_FS_MAX_PATH];
|
||||||
|
|
||||||
struct stat file_stat;
|
struct stat file_stat;
|
||||||
int fd;
|
int fd;
|
||||||
@ -192,15 +186,19 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If path invalid, return no such file */
|
/* Normalize path, return no-such-file if invalid */
|
||||||
if (__guac_rdpdr_fs_translate_path(device, path, path_buffer) == NULL)
|
if (guac_rdpdr_fs_normalize_path(path, normalized_path))
|
||||||
return GUAC_RDPDR_FS_ENOENT;
|
return GUAC_RDPDR_FS_ENOENT;
|
||||||
|
|
||||||
guac_client_log_info(device->rdpdr->client, "Path \"%s\" translated to \"%s\"",
|
/* Translate normalized path to real path */
|
||||||
path, path_buffer);
|
__guac_rdpdr_fs_translate_path(device, normalized_path, real_path);
|
||||||
|
|
||||||
|
guac_client_log_info(device->rdpdr->client,
|
||||||
|
"Path virtual=\"%s\" -> normalized=\"%s\", real=\"%s\"",
|
||||||
|
path, normalized_path, real_path);
|
||||||
|
|
||||||
/* Open file */
|
/* Open file */
|
||||||
fd = open(path_buffer, flags, mode);
|
fd = open(real_path, flags, mode);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return GUAC_RDPDR_FS_ENOENT;
|
return GUAC_RDPDR_FS_ENOENT;
|
||||||
|
|
||||||
@ -209,6 +207,7 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path,
|
|||||||
file = &(data->files[file_id]);
|
file = &(data->files[file_id]);
|
||||||
file->fd = fd;
|
file->fd = fd;
|
||||||
file->dir = NULL;
|
file->dir = NULL;
|
||||||
|
file->absolute_path = strdup(path);
|
||||||
|
|
||||||
/* Attempt to pull file information */
|
/* Attempt to pull file information */
|
||||||
if (fstat(fd, &file_stat) == 0) {
|
if (fstat(fd, &file_stat) == 0) {
|
||||||
@ -231,7 +230,7 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path,
|
|||||||
else {
|
else {
|
||||||
|
|
||||||
guac_client_log_info(device->rdpdr->client, "Unable to read information for \"%s\"",
|
guac_client_log_info(device->rdpdr->client, "Unable to read information for \"%s\"",
|
||||||
path_buffer);
|
real_path);
|
||||||
|
|
||||||
/* Init information to 0, lacking any alternative */
|
/* Init information to 0, lacking any alternative */
|
||||||
file->size = 0;
|
file->size = 0;
|
||||||
@ -267,6 +266,9 @@ void guac_rdpdr_fs_close(guac_rdpdr_device* device, int file_id) {
|
|||||||
/* Close file */
|
/* Close file */
|
||||||
close(file->fd);
|
close(file->fd);
|
||||||
|
|
||||||
|
/* Free name */
|
||||||
|
free(file->absolute_path);
|
||||||
|
|
||||||
/* Free ID back to pool */
|
/* Free ID back to pool */
|
||||||
guac_pool_free_int(data->file_id_pool, file_id);
|
guac_pool_free_int(data->file_id_pool, file_id);
|
||||||
data->open_files--;
|
data->open_files--;
|
||||||
@ -302,3 +304,86 @@ const char* guac_rdpdr_fs_read_dir(guac_rdpdr_device* device, int file_id) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_rdpdr_fs_normalize_path(const char* path, char* abs_path) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int path_depth = 0;
|
||||||
|
char path_component_data[GUAC_RDPDR_FS_MAX_PATH];
|
||||||
|
const char* path_components[64];
|
||||||
|
|
||||||
|
const char** current_path_component = &(path_components[0]);
|
||||||
|
const char* current_path_component_data = &(path_component_data[0]);
|
||||||
|
|
||||||
|
/* If original path is not absolute, normalization fails */
|
||||||
|
if (path[0] != '\\' && path[0] != '/')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Skip past leading slash */
|
||||||
|
path++;
|
||||||
|
|
||||||
|
/* Copy path into component data for parsing */
|
||||||
|
strncpy(path_component_data, path, GUAC_RDPDR_FS_MAX_PATH-1);
|
||||||
|
|
||||||
|
/* Find path components within path */
|
||||||
|
for (i=0; i<GUAC_RDPDR_FS_MAX_PATH; i++) {
|
||||||
|
|
||||||
|
/* If current character is a path separator, parse as component */
|
||||||
|
char c = path_component_data[i];
|
||||||
|
if (c == '/' || c == '\\' || c == 0) {
|
||||||
|
|
||||||
|
/* Terminate current component */
|
||||||
|
path_component_data[i] = 0;
|
||||||
|
|
||||||
|
/* If component refers to parent, just move up in depth */
|
||||||
|
if (strcmp(current_path_component_data, "..") == 0) {
|
||||||
|
if (path_depth > 0)
|
||||||
|
path_depth--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, if component not current directory, add to list */
|
||||||
|
else if (strcmp(current_path_component_data, ".") != 0)
|
||||||
|
path_components[path_depth++] = current_path_component_data;
|
||||||
|
|
||||||
|
/* If end of string, stop */
|
||||||
|
if (c == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Update start of next component */
|
||||||
|
current_path_component_data = &(path_component_data[i+1]);
|
||||||
|
|
||||||
|
} /* end if separator */
|
||||||
|
|
||||||
|
} /* end for each character */
|
||||||
|
|
||||||
|
/* If no components, the path could not be parsed */
|
||||||
|
if (path_depth == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Ensure last component is null-terminated */
|
||||||
|
path_component_data[i] = 0;
|
||||||
|
|
||||||
|
/* Convert components back into path */
|
||||||
|
for (; path_depth > 0; path_depth--) {
|
||||||
|
|
||||||
|
const char* filename = *(current_path_component++);
|
||||||
|
|
||||||
|
/* Add separator */
|
||||||
|
*(abs_path++) = '\\';
|
||||||
|
|
||||||
|
/* Copy string */
|
||||||
|
while (*filename != 0)
|
||||||
|
*(abs_path++) = *(filename++);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Terminate absolute path */
|
||||||
|
*(abs_path++) = 0;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_rdpdr_fs_convert_path(const char* parent, const char* rel_path, char* abs_path) {
|
||||||
|
/* STUB */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -160,6 +160,11 @@ typedef enum guac_rdpdr_fs_file_type {
|
|||||||
*/
|
*/
|
||||||
typedef struct guac_rdpdr_fs_file {
|
typedef struct guac_rdpdr_fs_file {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The absolute path, including filename, of this file.
|
||||||
|
*/
|
||||||
|
char* absolute_path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of this file.
|
* The type of this file.
|
||||||
*/
|
*/
|
||||||
@ -232,6 +237,12 @@ typedef struct guac_rdpdr_fs_data {
|
|||||||
*/
|
*/
|
||||||
void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr);
|
void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given relative path to an absolute path based on the given
|
||||||
|
* parent path. If the path cannot be converted, non-zero is returned.
|
||||||
|
*/
|
||||||
|
int guac_rdpdr_fs_convert_path(const char* parent, const char* rel_path, char* abs_path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next available file ID, or an error code less than zero
|
* Returns the next available file ID, or an error code less than zero
|
||||||
* if an error occurs.
|
* if an error occurs.
|
||||||
@ -244,6 +255,17 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path,
|
|||||||
*/
|
*/
|
||||||
void guac_rdpdr_fs_close(guac_rdpdr_device* device, int file_id);
|
void guac_rdpdr_fs_close(guac_rdpdr_device* device, int file_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an arbitrary path, which may contain ".." and ".", creates an
|
||||||
|
* absolute path which does NOT contain ".." or ".".
|
||||||
|
*/
|
||||||
|
int guac_rdpdr_fs_normalize_path(const char* path, char* abs_path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a parent path and a relative path, produces a normalized absolute path.
|
||||||
|
*/
|
||||||
|
int guac_rdpdr_fs_convert_path(const char* parent, const char* rel_path, char* abs_path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next filename within the directory having the given file ID,
|
* Returns the next filename within the directory having the given file ID,
|
||||||
* or NULL if no more files.
|
* or NULL if no more files.
|
||||||
|
@ -275,12 +275,11 @@ 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,
|
void guac_rdpdr_fs_process_query_directory(guac_rdpdr_device* device, wStream* input_stream,
|
||||||
int file_id, int completion_id) {
|
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]);*/
|
|
||||||
|
|
||||||
int fs_information_class, initial_query;
|
int fs_information_class, initial_query;
|
||||||
int path_length;
|
int path_length;
|
||||||
|
|
||||||
|
const char* entry_name;
|
||||||
|
|
||||||
/* Read main header */
|
/* Read main header */
|
||||||
Stream_Read_UINT32(input_stream, fs_information_class);
|
Stream_Read_UINT32(input_stream, fs_information_class);
|
||||||
Stream_Read_UINT8(input_stream, initial_query);
|
Stream_Read_UINT8(input_stream, initial_query);
|
||||||
@ -298,45 +297,51 @@ void guac_rdpdr_fs_process_query_directory(guac_rdpdr_device* device, wStream* i
|
|||||||
"Received initial dir query - class=0x%x, path_length=%i, path=%s",
|
"Received initial dir query - class=0x%x, path_length=%i, path=%s",
|
||||||
fs_information_class, path_length, path);
|
fs_information_class, path_length, path);
|
||||||
|
|
||||||
/* Open directory */
|
|
||||||
/*file->dir = fdopendir(file->fd);*/
|
|
||||||
|
|
||||||
/* FIXME: Handle error */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
guac_client_log_info(device->rdpdr->client,
|
guac_client_log_info(device->rdpdr->client,
|
||||||
"Received continued dir query - class=0x%x",
|
"Received continued dir query - class=0x%x",
|
||||||
fs_information_class);
|
fs_information_class);
|
||||||
|
|
||||||
/* Dispatch to appropriate class-specific handler */
|
/* If entry exists, call appriate handler to send data */
|
||||||
switch (fs_information_class) {
|
entry_name = guac_rdpdr_fs_read_dir(device, file_id);
|
||||||
|
if (entry_name != NULL) {
|
||||||
|
|
||||||
case FileDirectoryInformation:
|
guac_client_log_info(device->rdpdr->client, "NAME: %s", entry_name);
|
||||||
guac_rdpdr_fs_process_query_directory_info(device, input_stream,
|
|
||||||
file_id, completion_id);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FileFullDirectoryInformation:
|
/* Dispatch to appropriate class-specific handler */
|
||||||
guac_rdpdr_fs_process_query_full_directory_info(device, input_stream,
|
switch (fs_information_class) {
|
||||||
file_id, completion_id);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FileBothDirectoryInformation:
|
case FileDirectoryInformation:
|
||||||
guac_rdpdr_fs_process_query_both_directory_info(device, input_stream,
|
guac_rdpdr_fs_process_query_directory_info(device, input_stream,
|
||||||
file_id, completion_id);
|
file_id, completion_id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FileNamesInformation:
|
case FileFullDirectoryInformation:
|
||||||
guac_rdpdr_fs_process_query_names_info(device, input_stream,
|
guac_rdpdr_fs_process_query_full_directory_info(device, input_stream,
|
||||||
file_id, completion_id);
|
file_id, completion_id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FileBothDirectoryInformation:
|
||||||
|
guac_rdpdr_fs_process_query_both_directory_info(device, input_stream,
|
||||||
|
file_id, completion_id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FileNamesInformation:
|
||||||
|
guac_rdpdr_fs_process_query_names_info(device, input_stream,
|
||||||
|
file_id, completion_id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
guac_client_log_info(device->rdpdr->client,
|
||||||
|
"Unknown dir information class: 0x%x", fs_information_class);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
guac_client_log_info(device->rdpdr->client,
|
|
||||||
"Unknown dir information class: 0x%x", fs_information_class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Otherwise, send STATUS_NO_MORE_FILES */
|
||||||
|
else {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user