Add path normalization.
This commit is contained in:
parent
52f9bac805
commit
69d636860d
@ -61,11 +61,12 @@
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
/**
|
||||
* Translates an absolute Windows path to an absolute path which is within the "drive path"
|
||||
* specified in the connection settings.
|
||||
* Translates an absolute Windows virtual_path to an absolute virtual_path
|
||||
* which is within the "drive virtual_path" specified in the connection
|
||||
* settings.
|
||||
*/
|
||||
static char* __guac_rdpdr_fs_translate_path(guac_rdpdr_device* device,
|
||||
const char* path, char* path_buffer) {
|
||||
static void __guac_rdpdr_fs_translate_path(guac_rdpdr_device* device,
|
||||
const char* virtual_path, char* real_path) {
|
||||
|
||||
/* Get drive path */
|
||||
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;
|
||||
|
||||
/* 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++) {
|
||||
|
||||
/* Stop at end of string */
|
||||
char c = *path;
|
||||
char c = *(virtual_path++);
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
/* Disallow ".." */
|
||||
if (c == '.' && *(path-1) == '.')
|
||||
return NULL;
|
||||
|
||||
/* Translate backslashes to forward slashes */
|
||||
if (c == '\\')
|
||||
c = '/';
|
||||
|
||||
/* Store in real path buffer */
|
||||
*(path_buffer++)= c;
|
||||
|
||||
/* Next path character */
|
||||
path++;
|
||||
*(real_path++)= c;
|
||||
|
||||
}
|
||||
|
||||
/* Null terminator */
|
||||
*(path_buffer++)= 0;
|
||||
return path_buffer;
|
||||
*real_path = 0;
|
||||
|
||||
}
|
||||
|
||||
@ -120,7 +113,8 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path,
|
||||
int access, int create_disposition) {
|
||||
|
||||
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;
|
||||
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 */
|
||||
if (__guac_rdpdr_fs_translate_path(device, path, path_buffer) == NULL)
|
||||
/* Normalize path, return no-such-file if invalid */
|
||||
if (guac_rdpdr_fs_normalize_path(path, normalized_path))
|
||||
return GUAC_RDPDR_FS_ENOENT;
|
||||
|
||||
guac_client_log_info(device->rdpdr->client, "Path \"%s\" translated to \"%s\"",
|
||||
path, path_buffer);
|
||||
/* Translate normalized path to real path */
|
||||
__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 */
|
||||
fd = open(path_buffer, flags, mode);
|
||||
fd = open(real_path, flags, mode);
|
||||
if (fd == -1)
|
||||
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->fd = fd;
|
||||
file->dir = NULL;
|
||||
file->absolute_path = strdup(path);
|
||||
|
||||
/* Attempt to pull file information */
|
||||
if (fstat(fd, &file_stat) == 0) {
|
||||
@ -231,7 +230,7 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path,
|
||||
else {
|
||||
|
||||
guac_client_log_info(device->rdpdr->client, "Unable to read information for \"%s\"",
|
||||
path_buffer);
|
||||
real_path);
|
||||
|
||||
/* Init information to 0, lacking any alternative */
|
||||
file->size = 0;
|
||||
@ -267,6 +266,9 @@ void guac_rdpdr_fs_close(guac_rdpdr_device* device, int file_id) {
|
||||
/* Close file */
|
||||
close(file->fd);
|
||||
|
||||
/* Free name */
|
||||
free(file->absolute_path);
|
||||
|
||||
/* Free ID back to pool */
|
||||
guac_pool_free_int(data->file_id_pool, file_id);
|
||||
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 {
|
||||
|
||||
/**
|
||||
* The absolute path, including filename, of this file.
|
||||
*/
|
||||
char* absolute_path;
|
||||
|
||||
/**
|
||||
* The type of this file.
|
||||
*/
|
||||
@ -232,6 +237,12 @@ typedef struct guac_rdpdr_fs_data {
|
||||
*/
|
||||
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
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* 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,
|
||||
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 path_length;
|
||||
|
||||
const char* entry_name;
|
||||
|
||||
/* Read main header */
|
||||
Stream_Read_UINT32(input_stream, fs_information_class);
|
||||
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",
|
||||
fs_information_class, path_length, path);
|
||||
|
||||
/* Open directory */
|
||||
/*file->dir = fdopendir(file->fd);*/
|
||||
|
||||
/* FIXME: Handle error */
|
||||
|
||||
}
|
||||
else
|
||||
guac_client_log_info(device->rdpdr->client,
|
||||
"Received continued dir query - class=0x%x",
|
||||
fs_information_class);
|
||||
|
||||
/* Dispatch to appropriate class-specific handler */
|
||||
switch (fs_information_class) {
|
||||
/* If entry exists, call appriate handler to send data */
|
||||
entry_name = guac_rdpdr_fs_read_dir(device, file_id);
|
||||
if (entry_name != NULL) {
|
||||
|
||||
case FileDirectoryInformation:
|
||||
guac_rdpdr_fs_process_query_directory_info(device, input_stream,
|
||||
file_id, completion_id);
|
||||
break;
|
||||
guac_client_log_info(device->rdpdr->client, "NAME: %s", entry_name);
|
||||
|
||||
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, input_stream,
|
||||
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, input_stream,
|
||||
file_id, completion_id);
|
||||
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