Merge pull request #1449 from matt335672/filesys-reimplement

Significant remote file system improvements
This commit is contained in:
metalefty 2019-12-13 14:11:38 +09:00 committed by GitHub
commit 93da7c0d3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 4298 additions and 3320 deletions

View File

@ -225,6 +225,14 @@ Following parameters can be used in the \fB[Chansrv]\fR section.
Directory for drive redirection, relative to the user home directory.
Created if it doesn't exist. If not specified, defaults to \fIxrdp_client\fR.
.TP
\fBFileUmask\fR=\fImode\fR
Additional umask to apply to files in the \fBFuseMountName\fR directory.
The default value of 077 prevents other users on the system from reading
files on your redirected drives. This may not be approprate for all
environents, and so you can change this value to allow other users to
access your remote files if required.
.SH "SESSIONS VARIABLES"
All entries in the \fB[SessionVariables]\fR section are set as
environment variables in the user's session.

View File

@ -53,6 +53,8 @@ xrdp_chansrv_SOURCES = \
chansrv_common.h \
chansrv_fuse.c \
chansrv_fuse.h \
chansrv_xfs.c \
chansrv_xfs.h \
clipboard.c \
clipboard.h \
clipboard_common.h \
@ -65,6 +67,10 @@ xrdp_chansrv_SOURCES = \
irp.c \
irp.h \
mlog.h \
ms-erref.h \
ms-fscc.h \
ms-rdpefs.h \
ms-smb2.h \
rail.c \
rail.h \
smartcard.c \

View File

@ -407,7 +407,7 @@ process_message_channel_setup(struct stream *s)
if (g_rdpdr_index >= 0)
{
dev_redir_init();
devredir_init();
xfuse_init();
}
@ -458,7 +458,7 @@ process_message_channel_data(struct stream *s)
}
else if (chan_id == g_rdpdr_chan_id)
{
rv = dev_redir_data_in(s, chan_id, chan_flags, length, total_length);
rv = devredir_data_in(s, chan_id, chan_flags, length, total_length);
}
else if (chan_id == g_rail_chan_id)
{
@ -1412,7 +1412,7 @@ channel_thread_loop(void *in_val)
LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set"));
clipboard_deinit();
sound_deinit();
dev_redir_deinit();
devredir_deinit();
rail_deinit();
break;
}
@ -1434,7 +1434,7 @@ channel_thread_loop(void *in_val)
"trans_check_wait_objs error resetting"));
clipboard_deinit();
sound_deinit();
dev_redir_deinit();
devredir_deinit();
rail_deinit();
/* delete g_con_trans */
trans_delete(g_con_trans);
@ -1460,7 +1460,7 @@ channel_thread_loop(void *in_val)
api_con_trans_list_check_wait_objs();
xcommon_check_wait_objs();
sound_check_wait_objs();
dev_redir_check_wait_objs();
devredir_check_wait_objs();
xfuse_check_wait_objs();
timeout = -1;
num_objs = 0;
@ -1479,7 +1479,7 @@ channel_thread_loop(void *in_val)
&timeout);
xcommon_get_wait_objs(objs, &num_objs, &timeout);
sound_get_wait_objs(objs, &num_objs, &timeout);
dev_redir_get_wait_objs(objs, &num_objs, &timeout);
devredir_get_wait_objs(objs, &num_objs, &timeout);
xfuse_get_wait_objs(objs, &num_objs, &timeout);
get_timeout(&timeout);
} /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */

File diff suppressed because it is too large Load Diff

View File

@ -21,53 +21,94 @@
#include "arch.h"
/*
* a file or dir entry in the xrdp file system (opaque type externally) */
struct xrdp_inode;
#include "ms-erref.h"
/* Used to pass file info in to xfuse_devredir_add_file_or_dir()
*
* The string storage the name field points to is only valid
* for the duration of the xfuse_devredir_add_file_or_dir()
* call
*/
/* Used to pass file info back to chansrv_fuse from devredir */
struct file_attr
{
const char *name; /* Name of file or directory */
tui32 mode; /* File mode. */
size_t size; /* Size of file, in bytes. */
off_t size; /* Size of file, in bytes. */
time_t atime; /* Time of last access. */
time_t mtime; /* Time of last modification. */
time_t ctime; /* Time of last status change. */
};
/* Bitmask values used to identify individual elements in
* struct file_attr
*/
#define TO_SET_MODE (1<<0)
#define TO_SET_SIZE (1<<1)
#define TO_SET_ATIME (1<<2)
#define TO_SET_MTIME (1<<3)
#define TO_SET_ALL (TO_SET_MODE | TO_SET_SIZE | TO_SET_ATIME | TO_SET_MTIME)
/* Private type passed into and back-from devredir */
typedef struct xfuse_info XFUSE_INFO;
int xfuse_init(void);
int xfuse_deinit(void);
int xfuse_check_wait_objs(void);
int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout);
int xfuse_create_share(tui32 share_id, const char *dirname);
void xfuse_delete_share(tui32 share_id);
int xfuse_clear_clip_dir(void);
int xfuse_file_contents_range(int stream_id, const char *data, int data_bytes);
int xfuse_file_contents_size(int stream_id, int file_size);
int xfuse_add_clip_dir_item(const char *filename, int flags, int size, int lindex);
int xfuse_add_clip_dir_item(const char *filename,
int flags, int size, int lindex);
/* State pointer types (opaque outside this module), used for
* callback data
*/
struct state_dirscan;
struct state_lookup;
struct state_setattr;
struct state_open;
struct state_create;
struct state_read;
struct state_write;
struct state_remove;
struct state_rename;
struct state_close;
/* functions that are invoked from devredir */
struct xrdp_inode *xfuse_devredir_add_file_or_dir(
void *vp,
const struct file_attr *file_info);
void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus);
void xfuse_devredir_cb_lookup_entry(void *vp, tui32 IoStatus,
struct xrdp_inode *xinode);
void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, tui32 FileId);
void xfuse_devredir_cb_enum_dir_add_entry(
struct state_dirscan *fip,
const char *name,
const struct file_attr *fattr);
void xfuse_devredir_cb_enum_dir_done(struct state_dirscan *fip,
enum NTSTATUS IoStatus);
void xfuse_devredir_cb_lookup_entry(struct state_lookup *fip,
enum NTSTATUS IoStatus,
const struct file_attr *file_info);
void xfuse_devredir_cb_setattr(struct state_setattr *fip,
enum NTSTATUS IoStatus);
void xfuse_devredir_cb_create_file(struct state_create *fip,
enum NTSTATUS IoStatus,
tui32 DeviceId, tui32 FileId);
void xfuse_devredir_cb_open_file(struct state_open *fip,
enum NTSTATUS IoStatus,
tui32 DeviceId, tui32 FileId);
void xfuse_devredir_cb_read_file(struct state_read *fip,
const char *buf, size_t length);
void xfuse_devredir_cb_write_file(
void *vp,
tui32 IoStatus,
const char *buf,
struct state_write *fip,
enum NTSTATUS IoStatus,
off_t offset,
size_t length);
void xfuse_devredir_cb_read_file(void *vp, const char *buf, size_t length);
void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus);
void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus);
void xfuse_devredir_cb_file_close(void *vp);
void xfuse_devredir_cb_rmdir_or_file(struct state_remove *fip,
enum NTSTATUS IoStatus);
void xfuse_devredir_cb_rename_file(struct state_rename *fip,
enum NTSTATUS IoStatus);
void xfuse_devredir_cb_file_close(struct state_close *fip);
#endif

View File

@ -0,0 +1,909 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file implements the interface in chansrv_fuse_fs.h
*/
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include "os_calls.h"
#include "chansrv_xfs.h"
/*
* Skip this module if FUSE is not supported. A standards-compliant C
* translation unit must contain at least one declaration (C99:6.9), and we've
* fulfilled that requirement by this stage.
*/
#ifdef XRDP_FUSE
#define INODE_TABLE_ALLOCATION_INITIAL 4096
#define INODE_TABLE_ALLOCATION_GRANULARITY 100
/* inum of the delete pending directory */
#define DELETE_PENDING_ID 2
/*
* A double-linked list of inodes, sorted by inum
*
* The elements in the list are sorted in increasing inum order, as this
* allows a directory enumeration to be easily resumed if elements
* are removed or added. See xfs_readdir() for details on this.
*/
typedef struct xfs_inode_all XFS_INODE_ALL;
typedef struct xfs_list
{
XFS_INODE_ALL *begin;
XFS_INODE_ALL *end;
} XFS_LIST;
/*
* A complete inode, including the private elements used by the
* implementation
*/
typedef struct xfs_inode_all
{
XFS_INODE pub; /* Public elements */
/*
* Directory linkage elements
*
* Because we don't support hard-linking, elements can be stored in
* one and only one directory:-
*/
struct xfs_inode_all *parent; /* Parent inode */
struct xfs_inode_all *next; /* Next entry in parent */
struct xfs_inode_all *previous; /* Previous entry in parent */
XFS_LIST dir; /* Directory only - children */
/*
* Other private elements
*/
unsigned int open_count; /* Regular files only */
} XFS_INODE_ALL;
/* the xrdp file system in memory
*
* inode_table allows for O(1) access to any file based on the inum.
* Index 0 is unused, so we can use an inode of zero for
* an invalid inode, and avoid off-by-one errors index
* 1 is our '.' directory.
* 2 is the delete pending directory, where we can place
* inodes with a positive open count which are
* deleted.
* free_list List of free inode numbers. Allows for O(1) access to
* a free node, provided the free list is not empty.
*/
struct xfs_fs
{
XFS_INODE_ALL **inode_table; /* a table of entries; can grow. */
fuse_ino_t *free_list; /* Free inodes */
unsigned int inode_count; /* Current number of inodes */
unsigned int free_count; /* Size of free_list */
unsigned int generation; /* Changes when an inode is deleted */
};
/* A directory handle
*
* inum inum of the directory being scanned
* generation Generation of the inum we opened
*/
struct xfs_dir_handle
{
fuse_ino_t inum;
tui32 generation;
};
/* module based logging */
#define LOG_ERROR 0
#define LOG_INFO 1
#define LOG_DEBUG 2
#ifndef LOG_LEVEL
#define LOG_LEVEL LOG_ERROR
#endif
#define log_error(_params...) \
{ \
g_write("[%10.10u]: XFS %s: %d : ERROR: ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
}
#define log_always(_params...) \
{ \
g_write("[%10.10u]: XFS %s: %d : ALWAYS: ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
}
#define log_info(_params...) \
{ \
if (LOG_INFO <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: XFS %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
#define log_debug(_params...) \
{ \
if (LOG_DEBUG <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: XFS %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
/* ------------------------------------------------------------------------ */
static int
grow_xfs(struct xfs_fs *xfs, unsigned int extra_inodes)
{
int result = 0;
unsigned int new_count = xfs->inode_count + extra_inodes;
XFS_INODE_ALL **new_table;
fuse_ino_t *new_free_list;
new_table = (XFS_INODE_ALL **)
realloc(xfs->inode_table, new_count * sizeof(new_table[0]));
if (new_table != NULL)
{
unsigned int i;
for (i = xfs->inode_count ; i < new_count ; ++i)
{
new_table[i] = NULL;
}
xfs->inode_table = new_table;
new_free_list = (fuse_ino_t *)
realloc(xfs->free_list,
new_count * sizeof(new_free_list[0]));
if (new_free_list)
{
/* Add the new inodes in to the new_free_list, so the lowest
* number is allocated first
*/
i = new_count;
while (i > xfs->inode_count)
{
new_free_list[xfs->free_count++] = --i;
}
xfs->free_list = new_free_list;
xfs->inode_count = new_count;
result = 1;
}
}
return result;
}
/* ------------------------------------------------------------------------ */
static void
add_inode_to_list(XFS_LIST *list, XFS_INODE_ALL *xino)
{
fuse_ino_t inum = xino->pub.inum;
/* Find the element we need to insert after */
XFS_INODE_ALL *predecessor = list->end;
while (predecessor != NULL && predecessor->pub.inum > inum)
{
predecessor = predecessor->previous;
}
if (predecessor == NULL)
{
/* Inserting at the beginning */
/* Set up links in node */
xino->next = list->begin;
xino->previous = NULL;
/* Set up back-link to node */
if (list->begin == NULL)
{
/* We are the last node */
list->end = xino;
}
else
{
list->begin->previous = xino;
}
/* Set up forward-link to node */
list->begin = xino;
}
else
{
/* Set up links in node */
xino->next = predecessor->next;
xino->previous = predecessor;
/* Set up back-link to node */
if (predecessor->next == NULL)
{
list->end = xino;
}
else
{
predecessor->next->previous = xino;
}
/* Set up forward-link to node */
predecessor->next = xino;
}
}
/* ------------------------------------------------------------------------ */
static void
remove_inode_from_list(XFS_LIST *list, XFS_INODE_ALL *xino)
{
if (xino->previous == NULL)
{
/* First element */
list->begin = xino->next;
}
else
{
xino->previous->next = xino->next;
}
if (xino->next == NULL)
{
/* Last element */
list->end = xino->previous;
}
else
{
xino->next->previous = xino->previous;
}
}
/* ------------------------------------------------------------------------ */
static void
link_inode_into_directory_node(XFS_INODE_ALL *dinode, XFS_INODE_ALL *xino)
{
xino->parent = dinode;
add_inode_to_list(&dinode->dir, xino);
}
/* ------------------------------------------------------------------------ */
static void
unlink_inode_from_parent(XFS_INODE_ALL *xino)
{
remove_inode_from_list(&xino->parent->dir, xino);
xino->next = NULL;
xino->previous = NULL;
xino->parent = NULL;
}
/* ------------------------------------------------------------------------ */
struct xfs_fs *
xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
{
struct xfs_fs *xfs = g_new0(struct xfs_fs, 1);
XFS_INODE_ALL *xino1 = NULL;
XFS_INODE_ALL *xino2 = NULL;
if (xfs != NULL)
{
xfs->inode_count = 0;
xfs->free_count = 0;
xfs->inode_table = NULL;
xfs->free_list = NULL;
xfs->generation = 1;
if (!grow_xfs(xfs, INODE_TABLE_ALLOCATION_INITIAL) ||
(xino1 = g_new0(XFS_INODE_ALL, 1)) == NULL ||
(xino2 = g_new0(XFS_INODE_ALL, 1)) == NULL)
{
free(xino1);
free(xino2);
xfs_delete_xfs_fs(xfs);
xfs = NULL;
}
else
{
/*
* The use of grow_xfs to allocate the inode table will make
* inodes 0, 1 (FUSE_ROOT_ID) and 2 (DELETE_PENDING_ID) the first
* available free inodes. We can ignore these */
xfs->free_count -= 3;
xfs->inode_table[0] = NULL;
xfs->inode_table[FUSE_ROOT_ID] = xino1;
xfs->inode_table[DELETE_PENDING_ID] = xino2;
xino1->pub.inum = FUSE_ROOT_ID;
xino1->pub.mode = (S_IFDIR | 0777) & ~umask;
xino1->pub.uid = uid;
xino1->pub.gid = gid;
xino1->pub.size = 0;
xino1->pub.atime = time(0);
xino1->pub.mtime = xino1->pub.atime;
xino1->pub.ctime = xino1->pub.atime;
strcpy(xino1->pub.name, ".");
xino1->pub.generation = xfs->generation;
xino1->pub.device_id = 0;
/*
* FUSE_ROOT_ID has no parent rather than being a parent
* of itself. This is intentional */
xino1->parent = NULL;
xino1->next = NULL;
xino1->previous = NULL;
xino1->dir.begin = NULL;
xino1->dir.end = NULL;
xino2->pub.inum = DELETE_PENDING_ID;
xino2->pub.mode = (S_IFDIR | 0777) & ~umask;
xino2->pub.uid = uid;
xino2->pub.gid = gid;
xino2->pub.size = 0;
xino2->pub.atime = time(0);
xino2->pub.mtime = xino2->pub.atime;
xino2->pub.ctime = xino2->pub.atime;
strcpy(xino2->pub.name, ".delete-pending");
xino2->pub.generation = xfs->generation;
xino2->pub.device_id = 0;
xino2->parent = NULL;
xino2->next = NULL;
xino2->previous = NULL;
xino2->dir.begin = NULL;
xino2->dir.end = NULL;
/*
* Uncomment this line to make the .delete-pending
* directory visible to the user in the root
*/
/* link_inode_into_directory_node(xino1, xino2); */
}
}
return xfs;
}
/* ------------------------------------------------------------------------ */
void
xfs_delete_xfs_fs(struct xfs_fs *xfs)
{
if (xfs != NULL && xfs->inode_table != NULL)
{
size_t i;
for (i = 0 ; i < xfs->inode_count; ++i)
{
free(xfs->inode_table[i]);
}
}
free(xfs->inode_table);
free(xfs->free_list);
free(xfs);
}
/* ------------------------------------------------------------------------ */
XFS_INODE *
xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
const char *name, mode_t mode)
{
XFS_INODE *result = NULL;
XFS_INODE_ALL *parent = NULL;
/* Checks:-
* 1) the parent exists (and is a directory)
* 2) the caller is not inserting into the .delete-pending directory,
* 3) Name's not too long
* 4) Entry does not already exist
*/
if (parent_inum < xfs->inode_count &&
((parent = xfs->inode_table[parent_inum]) != NULL) &&
(parent->pub.mode & S_IFDIR) != 0 &&
parent_inum != DELETE_PENDING_ID &&
strlen(name) <= XFS_MAXFILENAMELEN &&
!xfs_lookup_in_dir(xfs, parent_inum, name))
{
/* Sanitise the mode so one-and-only-one of S_IFDIR and
* S_IFREG is set */
if ((mode & S_IFDIR) != 0)
{
mode = (mode & 0777) | S_IFDIR;
}
else
{
mode = (mode & 0777) | S_IFREG;
}
/* Space for a new entry? */
if (xfs->free_count > 0 ||
grow_xfs(xfs, INODE_TABLE_ALLOCATION_GRANULARITY))
{
XFS_INODE_ALL *xino = NULL;
if ((xino = g_new0(XFS_INODE_ALL, 1)) != NULL)
{
fuse_ino_t inum = xfs->free_list[--xfs->free_count];
if (xfs->inode_table[inum] != NULL)
{
log_error("Unexpected non-NULL value in inode table "
"entry %ld", inum);
}
xfs->inode_table[inum] = xino;
xino->pub.inum = inum;
xino->pub.mode = mode;
xino->pub.uid = parent->pub.uid;
xino->pub.gid = parent->pub.gid;
if (mode & S_IFDIR)
{
xino->pub.size = 4096;
}
else
{
xino->pub.size = 0;
}
xino->pub.atime = time(0);
xino->pub.mtime = xino->pub.atime;
xino->pub.ctime = xino->pub.atime;
strcpy(xino->pub.name, name);
xino->pub.generation = xfs->generation;
xino->pub.device_id = parent->pub.device_id;
xino->pub.lindex = 0;
xino->parent = NULL;
xino->next = NULL;
xino->previous = NULL;
link_inode_into_directory_node(parent, xino);
result = &xino->pub;
}
}
}
return result;
}
/* ------------------------------------------------------------------------ */
void
xfs_remove_directory_contents(struct xfs_fs *xfs, fuse_ino_t inum)
{
XFS_INODE_ALL *xino = NULL;
if (inum < xfs->inode_count &&
((xino = xfs->inode_table[inum]) != NULL) &&
((xino->pub.mode & S_IFDIR) != 0))
{
XFS_INODE_ALL *e;
while ((e = xino->dir.end) != NULL)
{
xfs_remove_entry(xfs, e->pub.inum);
}
}
}
/* ------------------------------------------------------------------------ */
void
xfs_remove_entry(struct xfs_fs *xfs, fuse_ino_t inum)
{
XFS_INODE_ALL *xino = NULL;
if (inum < xfs->inode_count &&
((xino = xfs->inode_table[inum]) != NULL))
{
if ((xino->pub.mode & S_IFDIR) != 0)
{
xfs_remove_directory_contents(xfs, inum);
}
unlink_inode_from_parent(xino);
if ((xino->pub.mode & S_IFREG) != 0 && xino->open_count > 0)
{
link_inode_into_directory_node(
xfs->inode_table[DELETE_PENDING_ID], xino);
}
else
{
xfs->free_list[xfs->free_count++] = inum;
xfs->inode_table[inum] = NULL;
/*
* Bump the generation when we return an inum to the free list,
* so that the caller can distinguish re-uses of the same inum.
*/
++xfs->generation;
free(xino);
}
}
}
/* ------------------------------------------------------------------------ */
XFS_INODE *
xfs_get(struct xfs_fs *xfs, fuse_ino_t inum)
{
return (inum < xfs->inode_count) ? &xfs->inode_table[inum]->pub : NULL;
}
/* ------------------------------------------------------------------------ */
char *
xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum)
{
char *result = NULL;
XFS_INODE_ALL *xino = NULL;
if (inum < xfs->inode_count &&
((xino = xfs->inode_table[inum]) != NULL))
{
if (xino->pub.inum == FUSE_ROOT_ID)
{
return strdup("/");
}
else
{
/*
* Add up the lengths of all the names up to the root,
* allowing one extra char for a '/' prefix for each element
*/
size_t len = 0;
XFS_INODE_ALL *p;
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
{
len += strlen(p->pub.name);
++len; /* Allow for '/' prefix */
}
result = (char *) malloc(len + 1);
if (result != NULL)
{
/* Construct the path from the end */
char *end = result + len;
*end = '\0';
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
{
len = strlen(p->pub.name);
end -= (len + 1);
*end = '/';
memcpy(end + 1, p->pub.name, len);
}
}
}
}
return result;
}
/* ------------------------------------------------------------------------ */
XFS_INODE *
xfs_lookup_in_dir(struct xfs_fs *xfs, fuse_ino_t inum, const char *name)
{
XFS_INODE_ALL *xino;
XFS_INODE *result = NULL;
if (inum < xfs->inode_count &&
((xino = xfs->inode_table[inum]) != NULL) &&
(xino->pub.mode & S_IFDIR) != 0)
{
XFS_INODE_ALL *p;
for (p = xino->dir.begin ; p != NULL; p = p->next)
{
if (strcmp(p->pub.name, name) == 0)
{
result = &p->pub;
break;
}
}
}
return result;
}
/* ------------------------------------------------------------------------ */
int
xfs_is_dir_empty(struct xfs_fs *xfs, fuse_ino_t inum)
{
XFS_INODE_ALL *xino = NULL;
int result = 0;
if (inum < xfs->inode_count &&
((xino = xfs->inode_table[inum]) != NULL) &&
(xino->pub.mode & S_IFDIR) != 0)
{
result = (xino->dir.begin == NULL);
}
return result;
}
/* ------------------------------------------------------------------------ */
unsigned int
xfs_is_under(struct xfs_fs *xfs, fuse_ino_t dir, fuse_ino_t entry)
{
unsigned int result = 0;
XFS_INODE_ALL *dxino = NULL;
XFS_INODE_ALL *exino = NULL;
if (dir < xfs->inode_count &&
((dxino = xfs->inode_table[dir]) != NULL) &&
(dxino->pub.mode & S_IFDIR) != 0 &&
entry < xfs->inode_count &&
((exino = xfs->inode_table[entry]) != NULL))
{
unsigned int count = 0;
while (exino != NULL && exino != dxino)
{
++count;
exino = exino->parent;
}
if (exino != NULL)
{
result = count;
}
}
return result;
}
/* ------------------------------------------------------------------------ */
struct xfs_dir_handle *
xfs_opendir(struct xfs_fs *xfs, fuse_ino_t dir)
{
XFS_INODE_ALL *xino = NULL;
struct xfs_dir_handle *result = NULL;
if (dir < xfs->inode_count &&
((xino = xfs->inode_table[dir]) != NULL) &&
(xino->pub.mode & S_IFDIR) != 0)
{
result = g_new0(struct xfs_dir_handle, 1);
if (result)
{
result->inum = xino->pub.inum;
result->generation = xino->pub.generation;
}
}
return result;
}
/* ------------------------------------------------------------------------ */
XFS_INODE *
xfs_readdir(struct xfs_fs *xfs, struct xfs_dir_handle *handle, off_t *off)
{
XFS_INODE_ALL *result = NULL;
XFS_INODE_ALL *dxino = NULL;
XFS_INODE_ALL *xino = NULL;
/* Check the direcory is still valid */
if (handle->inum < xfs->inode_count &&
((dxino = xfs->inode_table[handle->inum]) != NULL) &&
(dxino->pub.mode & S_IFDIR) != 0 &&
handle->generation == dxino->pub.generation)
{
fuse_ino_t inum;
if (*off == (off_t) -1)
{
/* We're at the end already */
}
else if ((inum = *off) == 0)
{
/* First call */
result = dxino->dir.begin;
}
else if (inum < xfs->inode_count &&
(xino = xfs->inode_table[inum]) != 0 &&
xino->parent == dxino)
{
/* The node we're pointing to is still valid */
result = xino;
}
else
{
/*
* The file we wanted has been pulled out from under us.
* We will look forward in the inode table to try to
* discover the next inode in the directory. Because
* files are stored in inode order, this guarantees
* we'll meet POSIX requirements.
*/
for (inum = inum + 1 ; inum < xfs->inode_count ; ++inum)
{
if ((xino = xfs->inode_table[inum]) != 0 &&
xino->parent == dxino)
{
result = xino;
break;
}
}
}
}
/* Update the offset */
if (result == NULL || result->next == NULL)
{
/* We're done */
*off = (off_t) -1;
}
else
{
*off = (off_t)result->next->pub.inum;
}
/* Caller only sees public interface to the result */
return (result) ? &result->pub : NULL;
}
/* ------------------------------------------------------------------------ */
void
xfs_closedir(struct xfs_fs *xfs, struct xfs_dir_handle *handle)
{
free(handle);
}
/* ------------------------------------------------------------------------ */
void
xfs_increment_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum)
{
XFS_INODE_ALL *xino;
if (inum < xfs->inode_count &&
((xino = xfs->inode_table[inum]) != NULL) &&
(xino->pub.mode & S_IFREG) != 0)
{
++xino->open_count;
}
}
/* ------------------------------------------------------------------------ */
void
xfs_decrement_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum)
{
XFS_INODE_ALL *xino;
if (inum < xfs->inode_count &&
((xino = xfs->inode_table[inum]) != NULL) &&
(xino->pub.mode & S_IFREG) != 0)
{
if (xino->open_count > 0)
{
--xino->open_count;
}
if (xino->open_count == 0 &&
xino->parent == xfs->inode_table[DELETE_PENDING_ID])
{
/* We can get rid of this one now */
xfs_remove_entry(xfs, inum);
}
}
}
/* ------------------------------------------------------------------------ */
unsigned int
xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum)
{
unsigned int result = 0;
XFS_INODE_ALL *xino;
if (inum < xfs->inode_count &&
((xino = xfs->inode_table[inum]) != NULL) &&
(xino->pub.mode & S_IFREG) != 0)
{
result = xino->open_count;
}
return result;
}
/* ------------------------------------------------------------------------ */
void
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id)
{
fuse_ino_t inum;
XFS_INODE_ALL *xino;
if (device_id != 0)
{
/* Using xfs_remove_entry() is convenient, but it recurses
* in to directories. To make sure all entries are removed, set the
* open_count of all affected files to 0 first
*/
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
{
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.device_id == device_id &&
(xino->pub.mode & S_IFREG) != 0)
{
xino->open_count = 0;
}
}
/* Now we can be sure everything will be deleted correctly */
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
{
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.device_id == device_id)
{
xfs_remove_entry(xfs, xino->pub.inum);
}
}
}
}
/* ------------------------------------------------------------------------ */
int
xfs_check_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
fuse_ino_t new_parent_inum, const char *name)
{
XFS_INODE_ALL *xino;
XFS_INODE_ALL *parent;
return
(strlen(name) <= XFS_MAXFILENAMELEN &&
inum < xfs->inode_count &&
((xino = xfs->inode_table[inum]) != NULL) &&
new_parent_inum != DELETE_PENDING_ID &&
new_parent_inum < xfs->inode_count &&
((parent = xfs->inode_table[new_parent_inum]) != NULL) &&
(parent->pub.mode & S_IFDIR) != 0 &&
xfs_is_under(xfs, inum, new_parent_inum) == 0);
}
/* ------------------------------------------------------------------------ */
int
xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
fuse_ino_t new_parent_inum, const char *name)
{
int result = EINVAL;
XFS_INODE_ALL *xino;
XFS_INODE_ALL *parent;
XFS_INODE *dest;
if (xfs_check_move_entry(xfs, inum, new_parent_inum, name))
{
xino = xfs->inode_table[inum];
parent = xfs->inode_table[new_parent_inum];
if (xino->parent != parent)
{
/* We're moving between directories */
/* Does the target name already exist in the destination? */
if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL)
{
xfs_remove_entry(xfs, dest->inum);
}
unlink_inode_from_parent(xino);
link_inode_into_directory_node(parent, xino);
strcpy(xino->pub.name, name);
}
else if (strcmp(xino->pub.name, name) != 0)
{
/* Same directory, but name has changed */
if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL)
{
xfs_remove_entry(xfs, dest->inum);
}
strcpy(xino->pub.name, name);
}
result = 0;
}
return result;
}
#endif /* XRDP_FUSE */

View File

@ -0,0 +1,321 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is the interface to the FUSE file system used by
* chansrv
*/
#ifndef _CHANSRV_XFS
#define _CHANSRV_XFS
/* Skip this include if there's no FUSE */
#ifdef XRDP_FUSE
#include <stddef.h>
#include <fuse_lowlevel.h>
#include <time.h>
#include "arch.h"
#define XFS_MAXFILENAMELEN 255
/*
* Incomplete types for the public interface
*/
struct xfs_fs;
struct xfs_dir_handle;
typedef struct xfs_inode
{
fuse_ino_t inum; /* File serial number. */
mode_t mode; /* File mode. */
uid_t uid; /* User ID of the file's owner. */
gid_t gid; /* Group ID of the file's group. */
off_t size; /* Size of file, in bytes. */
time_t atime; /* Time of last access. */
time_t mtime; /* Time of last modification. */
time_t ctime; /* Time of last status change. */
char name[XFS_MAXFILENAMELEN + 1]; /* Short name */
tui32 generation; /* Changes if inode is reused */
tui32 device_id; /* for file system redirection
* Non-redirected devices are guaranteed
* to have a device_id or zero */
int lindex; /* used in clipboard operations */
} XFS_INODE;
/*
* Create a new filesystem instance
*
* @param umask Umask to apply to initial data structures
* @param uid Owner UID for initial root directory
* @param gid Owner GID for initial root directory
* @return Pointer to instance, or NULL if no memory
*/
struct xfs_fs *
xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid);
/*
* Delete a filesystem instance
*
* @param xfs Filesystem instance
*/
void
xfs_delete_xfs_fs(struct xfs_fs *xfs);
/*
* Add an entry to the filesystem
*
* The returned element has default values inherited from the parent
*
* The specified mode is sanitised in that:-
* - Bits other than the lowest nine permissions bits, the directory
* bit (S_IFDIR) and the regular bit (S_IFREG) are cleared.
* - S_IFREG is cleared if S_IFDIR is set
* - S_IFREG is set if neither S_IFDIR or S_IFREG is set
*
* NULL is returned for one of the following conditions:-
* - the parent does not exist
* - the parent is not a directory
* - the name length exceeds XFS_MAXFILENAMELEN
* - the entry already exists
* - memory is exhausted.
*
* @param xfs filesystem instance
* @param parent_inode parent inode
* @param name Name of entry
* @param mode Initial mode for file.
* @return inode, or NULL
*/
XFS_INODE *
xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
const char *name, mode_t mode);
/*
* Delete the contents of a directory
*
* If normal files are opened when they are deleted, the inode is not
* released until the open count goes to zero.
*
* @param xfs filesystem instance
* @param inode Reference to entry to delete
*
*/
void
xfs_remove_directory_contents(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Delete an entry from the filesystem
*
* If normal files are opened when they are deleted, the inode is not
* released until the open count goes to zero.
*
* For directories, the contents are removed first.
*
* @param xfs filesystem instance
* @param inode Reference to entry to delete
*
*/
void
xfs_remove_entry(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Get an XFS_INODE for an inum
*
* @param xfs filesystem instance
* @param inum Inumber
* @return Pointer to XFS_INODE
*/
XFS_INODE *
xfs_get(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Get the full path for an inum
*
* The path is dynamically allocated, and must be freed after use
*
* @param xfs filesystem instance
* @param inum Inumber to get path for
* @return Full path (free after use)
*/
char *
xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Lookup a file in a directory
*
* @param xfs filesystem instance
* @param inum Inumber of the directory
* @param name Name of the file to lookup
* @return Pointer to XFS_INODE if found
*/
XFS_INODE *
xfs_lookup_in_dir(struct xfs_fs *xfs, fuse_ino_t inum, const char *name);
/*
* Inquires as to whether a directory is empty.
*
* The caller must check that the inum is actually a directory, or
* the result is undefined.
*
* @param xfs filesystem instance
* @param inum Inumber of the directory
* @return True if the directory is empty
*/
int
xfs_is_dir_empty(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Inquires as to whether an entry is under a directory.
*
* This can be used to check for invalid renames, where we try to
* rename a directory into one of its sub-directories.
*
* Returned value means one of the following:-
* 0 Entry is not related to the directory
* 1 Entry is an immediate member of the directory
* 2.. Entry is a few levels below the directory
*
* @param xfs filesystem instance
* @param dir Inumber of the directory
* @param entry Inumber of the entry
* @return Nesting count of entry in the directory, or 0 for
* no nesting
*/
unsigned int
xfs_is_under(struct xfs_fs *xfs, fuse_ino_t dir, fuse_ino_t entry);
/*
* Opens a directory for reading
*
* @param xfs filesystem instance
* @param dir Inumber of the directory
* @return handle to be passed to xfs_readdir() and xfs_closedir()
*/
struct xfs_dir_handle *
xfs_opendir(struct xfs_fs *xfs, fuse_ino_t dir);
/*
* Gets the next entry from a directory
*
* This function is safe to call while the filesystem is being modified.
* Whether files added or removed from the directory in question are
* returned or not is unspecified by this interface.
*
* @param xfs filesystem instance
* @param handle Handle from xfs_opendir
* @param off Offset (by reference). Pass in zero to get the first
* entry. After the call, the offset is updated so that
* the next call gets the next entry.
*
* @return pointer to details of file entry, or NULL if no more
* entries are available.
*/
XFS_INODE *
xfs_readdir(struct xfs_fs *xfs, struct xfs_dir_handle *handle, off_t *off);
/*
* Closes a directory opened for reading
*
* @param xfs filesystem instance
* @param handle Earlier result of readdir() call
*/
void
xfs_closedir(struct xfs_fs *xfs, struct xfs_dir_handle *handle);
/*
* Increment the file open count
*
* The file open count is used to be sure when an entry can be deleted from
* the data structures. It allows us to remove an entry while still retaining
* enough state to manage the file
*
* This call is only necessary for regular files - not directories
*
* @param xfs filesystem instance
* @param inum File to increment the count of
*/
void
xfs_increment_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Decrement the file open count
*
* This call will ensure that deleted inodes are cleared up at the appropriate
* time.
*
* This call is only necessary for regular files - not directories
*
* @param xfs filesystem instance
* @param inum File to decrement the count of
*/
void
xfs_decrement_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Return the file open count for a regular file
*/
unsigned int
xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Deletes all entries with the matching device id
*
* Files are deleted even if they are open
*
* The specified device_id must be non-zero so that the root
* filesystem is not deleted!
*
* @param device_id Device ID
*/
void
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id);
/*
* Check an entry move will be successful
*
* A move will fail if:-
* - Any of the parameters are invalid
* - if the entry is a directory, and the new parent is below the
* entry in the existing hierarchy.
*
* @param xfs filesystem instance
* @param inum Inumber of entry
* @param new_parent New parent
* @param name New name
*
* @result != 0 if all looks OK
*/
int
xfs_check_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
fuse_ino_t new_parent_inum, const char *name);
/*
* Move (rename) an entry
*
* @param xfs filesystem instance
* @param inum Inumber of entry
* @param new_parent New parent
* @param name New name
*
* @result 0, or a suitable errno value.
*/
int
xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
fuse_ino_t new_parent_inum, const char *name);
#endif /* XRDP_FUSE */
#endif /* _CHANSRV_XFS */

File diff suppressed because it is too large Load Diff

View File

@ -18,334 +18,80 @@
* limitations under the License.
*/
// LK_TODO dev_redir_xxx should become devredir_xxx
#if !defined(DEVREDIR_H)
#define DEVREDIR_H
#include "irp.h"
#include "ms-rdpefs.h"
#define USE_SHORT_NAMES_IN_DIR_LISTING
int devredir_init(void);
int devredir_deinit(void);
FUSE_DATA *devredir_fuse_data_peek(IRP *irp);
FUSE_DATA *devredir_fuse_data_dequeue(IRP *irp);
int devredir_fuse_data_enqueue(IRP *irp, void *vp);
int devredir_data_in(struct stream* s, int chan_id, int chan_flags,
int length, int total_length);
int dev_redir_init(void);
int dev_redir_deinit(void);
int dev_redir_data_in(struct stream* s, int chan_id, int chan_flags,
int length, int total_length);
int dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout);
int dev_redir_check_wait_objs(void);
void dev_redir_send_server_core_cap_req(void);
void dev_redir_send_server_clientID_confirm(void);
void dev_redir_send_server_user_logged_on(void);
void devredir_send_server_device_announce_resp(tui32 device_id);
void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id,
tui32 InitialQuery, char *Path);
int dev_redir_send_drive_create_request(tui32 device_id,
const char *path,
tui32 DesiredAccess,
tui32 CreateOptions,
tui32 CreateDisposition,
tui32 completion_id);
int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId,
tui32 DeviceId,
tui32 FileId,
tui32 CompletionId,
tui32 MajorFunction,
tui32 MinorFunc,
int pad_len);
void devredir_proc_client_devlist_announce_req(struct stream *s);
void dev_redir_proc_client_core_cap_resp(struct stream *s);
void dev_redir_proc_device_iocompletion(struct stream *s);
void dev_redir_proc_query_dir_response(IRP *irp,
struct stream *s,
tui32 DeviceId,
tui32 CompletionId,
tui32 IoStatus);
int devredir_get_wait_objs(tbus* objs, int* count, int* timeout);
int devredir_check_wait_objs(void);
/* misc stuff */
void devredir_insert_DeviceIoRequest(struct stream *s,
tui32 DeviceId,
tui32 FileId,
tui32 CompletionId,
tui32 MajorFunction,
tui32 MinorFunction);
enum IRP_MJ MajorFunction,
enum IRP_MN MinorFunction);
void devredir_cvt_slash(char *path);
void devredir_cvt_to_unicode(char *unicode, const char *path);
void devredir_cvt_from_unicode_len(char *path, char *unicode, int len);
int dev_redir_string_ends_with(const char *string, char c);
void devredir_insert_RDPDR_header(struct stream *s, tui16 Component,
tui16 PacketId);
/* State pointer types (opaque outside this module), used for
* callback data
*/
struct state_dirscan;
struct state_lookup;
struct state_setattr;
struct state_open;
struct state_create;
struct state_read;
struct state_write;
struct state_remove;
struct state_close;
/* called from FUSE module */
int dev_redir_get_dir_listing(void *fusep, tui32 device_id, const char *path);
int dev_redir_lookup_entry(void *fusep, tui32 device_id, const char *dirpath,
const char *entry);
int devredir_get_dir_listing(struct state_dirscan *fusep, tui32 device_id,
const char *path);
int dev_redir_file_open(void *fusep, tui32 device_id, const char *path,
int mode, int type, const char *gen_buf);
int devredir_lookup_entry(struct state_lookup *fusep, tui32 device_id,
const char *path);
int devredir_file_close(void *fusep, tui32 device_id, tui32 file_id);
int devredir_setattr_for_entry(
struct state_setattr *fusep, tui32 device_id,
const char *filename,
const struct file_attr *fattr,
tui32 to_set);
int devredir_file_read(void *fusep, tui32 device_id, tui32 FileId,
int devredir_file_create(
struct state_create *fusep, tui32 device_id,
const char *path, int mode);
int devredir_file_open(struct state_open *fusep, tui32 device_id,
const char *path, int flags);
int devredir_file_close(struct state_close *fusep, tui32 device_id,
tui32 file_id);
int devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId,
tui32 Length, tui64 Offset);
int
dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId,
devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
const char *buf, int Length, tui64 Offset);
int devredir_file_rename(
struct state_rename *fusep, tui32 device_id,
const char *old_name,
const char *new_name);
int
devredir_rmdir_or_file(void *fusep, tui32 device_id, const char *path, int mode);
/*
* RDPDR_HEADER definitions
*/
/* device redirector core component; most of the packets in this protocol */
/* are sent under this component ID */
#define RDPDR_CTYP_CORE 0x4472
/* printing component. the packets that use this ID are typically about */
/* printer cache management and identifying XPS printers */
#define RDPDR_CTYP_PRN 0x5052
/* Server Announce Request, as specified in section 2.2.2.2 */
#define PAKID_CORE_SERVER_ANNOUNCE 0x496E
/* Client Announce Reply and Server Client ID Confirm, as specified in */
/* sections 2.2.2.3 and 2.2.2.6. */
#define PAKID_CORE_CLIENTID_CONFIRM 0x4343
/* Client Name Request, as specified in section 2.2.2.4 */
#define PAKID_CORE_CLIENT_NAME 0x434E
/* Client Device List Announce Request, as specified in section 2.2.2.9 */
#define PAKID_CORE_DEVICELIST_ANNOUNCE 0x4441
/* Server Device Announce Response, as specified in section 2.2.2.1 */
#define PAKID_CORE_DEVICE_REPLY 0x6472
/* Device I/O Request, as specified in section 2.2.1.4 */
#define PAKID_CORE_DEVICE_IOREQUEST 0x4952
/* Device I/O Response, as specified in section 2.2.1.5 */
#define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943
/* Server Core Capability Request, as specified in section 2.2.2.7 */
#define PAKID_CORE_SERVER_CAPABILITY 0x5350
/* Client Core Capability Response, as specified in section 2.2.2.8 */
#define PAKID_CORE_CLIENT_CAPABILITY 0x4350
/* Client Drive Device List Remove, as specified in section 2.2.3.2 */
#define PAKID_CORE_DEVICELIST_REMOVE 0x444D
/* Add Printer Cachedata, as specified in [MS-RDPEPC] section 2.2.2.3 */
#define PAKID_PRN_CACHE_DATA 0x5043
/* Server User Logged On, as specified in section 2.2.2.5 */
#define PAKID_CORE_USER_LOGGEDON 0x554C
/* Server Printer Set XPS Mode, as specified in [MS-RDPEPC] section 2.2.2.2 */
#define PAKID_PRN_USING_XPS 0x5543
/*
* Capability header definitions
*/
#define CAP_GENERAL_TYPE 0x0001 /* General cap set - GENERAL_CAPS_SET */
#define CAP_PRINTER_TYPE 0x0002 /* Print cap set - PRINTER_CAPS_SET */
#define CAP_PORT_TYPE 0x0003 /* Port cap set - PORT_CAPS_SET */
#define CAP_DRIVE_TYPE 0x0004 /* Drive cap set - DRIVE_CAPS_SET */
#define CAP_SMARTCARD_TYPE 0x0005 /* Smart card cap set - SMARTCARD_CAPS_SET */
/* client minor versions */
#define RDP_CLIENT_50 0x0002
#define RDP_CLIENT_51 0x0005
#define RDP_CLIENT_52 0x000a
#define RDP_CLIENT_60_61 0x000c
/* used in device announce list */
#define RDPDR_DTYP_SERIAL 0x0001
#define RDPDR_DTYP_PARALLEL 0x0002
#define RDPDR_DTYP_PRINT 0x0004
#define RDPDR_DTYP_FILESYSTEM 0x0008
#define RDPDR_DTYP_SMARTCARD 0x0020
/*
* DesiredAccess Mask [MS-SMB2] section 2.2.13.1.1
*/
#define DA_FILE_READ_DATA 0x00000001
#define DA_FILE_WRITE_DATA 0x00000002
#define DA_FILE_APPEND_DATA 0x00000004
#define DA_FILE_READ_EA 0x00000008 /* rd extended attributes */
#define DA_FILE_WRITE_EA 0x00000010 /* wr extended attributes */
#define DA_FILE_EXECUTE 0x00000020
#define DA_FILE_READ_ATTRIBUTES 0x00000080
#define DA_FILE_WRITE_ATTRIBUTES 0x00000100
#define DA_DELETE 0x00010000
#define DA_READ_CONTROL 0x00020000 /* rd security descriptor */
#define DA_WRITE_DAC 0x00040000
#define DA_WRITE_OWNER 0x00080000
#define DA_SYNCHRONIZE 0x00100000
#define DA_ACCESS_SYSTEM_SECURITY 0x01000000
#define DA_MAXIMUM_ALLOWED 0x02000000
#define DA_GENERIC_ALL 0x10000000
#define DA_GENERIC_EXECUTE 0x20000000
#define DA_GENERIC_WRITE 0x40000000
#define DA_GENERIC_READ 0x80000000
/*
* CreateOptions Mask [MS-SMB2] section 2.2.13 SMB2 CREATE Request
*/
enum CREATE_OPTIONS
{
CO_FILE_DIRECTORY_FILE = 0x00000001,
CO_FILE_WRITE_THROUGH = 0x00000002,
CO_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020,
CO_FILE_DELETE_ON_CLOSE = 0x00001000
};
/*
* CreateDispositions Mask [MS-SMB2] section 2.2.13
*/
#define CD_FILE_SUPERSEDE 0x00000000
#define CD_FILE_OPEN 0x00000001
#define CD_FILE_CREATE 0x00000002
#define CD_FILE_OPEN_IF 0x00000003
#define CD_FILE_OVERWRITE 0x00000004
#define CD_FILE_OVERWRITE_IF 0x00000005
/*
* Device I/O Request MajorFunction definitions
*/
#define IRP_MJ_CREATE 0x00000000
#define IRP_MJ_CLOSE 0x00000002
#define IRP_MJ_READ 0x00000003
#define IRP_MJ_WRITE 0x00000004
#define IRP_MJ_DEVICE_CONTROL 0x0000000E
#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0000000A
#define IRP_MJ_SET_VOLUME_INFORMATION 0x0000000B
#define IRP_MJ_QUERY_INFORMATION 0x00000005
#define IRP_MJ_SET_INFORMATION 0x00000006
#define IRP_MJ_DIRECTORY_CONTROL 0x0000000C
#define IRP_MJ_LOCK_CONTROL 0x00000011
/*
* Device I/O Request MinorFunction definitions
*
* Only valid when MajorFunction code = IRP_MJ_DIRECTORY_CONTROL
*/
#define IRP_MN_QUERY_DIRECTORY 0x00000001
#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x00000002
/*
* NTSTATUS codes (used by IoStatus) - see section 2.3 of MS-ERREF
*/
#define NT_STATUS_SUCCESS 0x00000000
#define NT_STATUS_UNSUCCESSFUL 0xC0000001
#define NT_STATUS_NO_SUCH_FILE 0xC000000F
#define NT_STATUS_ACCESS_DENIED 0xC0000022
#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000033
#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034
/*
* File system ioctl codes
* MS-FSCC section 2.3 FSCTL Structures
*/
#define FSCTL_DELETE_OBJECT_ID 0x900a0
/*
* CompletionID types, used in IRPs to indicate I/O operation
*/
enum COMPLETION_ID
{
CID_CREATE_DIR_REQ = 1,
CID_DIRECTORY_CONTROL,
CID_CREATE_OPEN_REQ,
CID_READ,
CID_WRITE,
CID_CLOSE,
CID_FILE_CLOSE,
CID_RMDIR_OR_FILE,
CID_RMDIR_OR_FILE_RESP,
CID_RENAME_FILE,
CID_RENAME_FILE_RESP,
CID_LOOKUP_BASIC_ENTRY,
CID_LOOKUP_STD_ENTRY,
CID_LOOKUP_ENTRY_RESP
};
enum FS_INFORMATION_CLASS
{
FileBasicInformation = 0x00000004, /* set atime, mtime, ctime etc */
FileStandardInformation = 0x00000005, /* Alloc size, EOF #links, etc */
FileEndOfFileInformation = 0x00000014, /* set EOF info */
FileDispositionInformation = 0x0000000D, /* mark a file for deletion */
FileRenameInformation = 0x0000000A, /* rename a file */
FileAllocationInformation = 0x00000013 /* set file allocation size */
};
/*
* constants for drive dir query
*/
/* Basic information about a file or directory. Basic information is */
/* defined as the file's name, time stamp, and size, or its attributes */
#define FileDirectoryInformation 0x00000001
/* Full information about a file or directory. Full information is defined */
/* as all the basic information, plus extended attribute size. */
#define FileFullDirectoryInformation 0x00000002
/* Basic information plus extended attribute size and short name */
/* about a file or directory. */
#define FileBothDirectoryInformation 0x00000003
/* Detailed information on the names of files in a directory. */
#define FileNamesInformation 0x0000000C
/*
* NTSTATUS Codes of interest to us
*/
/* No more files were found which match the file specification */
#define STATUS_NO_MORE_FILES 0x80000006
/* Windows file attributes */
#define W_FILE_ATTRIBUTE_DIRECTORY 0x00000010
#define W_FILE_ATTRIBUTE_READONLY 0x00000001
#define WINDOWS_TO_LINUX_FILE_PERM(_a) \
(((_a) & W_FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR | 0100 : S_IFREG) |\
(((_a) & W_FILE_ATTRIBUTE_READONLY) ? 0444 : 0644)
/* Windows time starts on Jan 1, 1601 */
/* Linux time starts on Jan 1, 1970 */
#define EPOCH_DIFF 11644473600LL
#define WINDOWS_TO_LINUX_TIME(_t) ((_t) / 10000000) - EPOCH_DIFF;
#define OP_RENAME_FILE 0x01
devredir_rmdir_or_file(struct state_remove *fusep, tui32 device_id,
const char *path);
#endif

View File

@ -105,32 +105,67 @@ IRP * devredir_irp_new(void)
}
/**
* Clone specified IRP
* Create a new IRP with a copied pathname, and append to linked list.
*
* Allocation is made in such a way that the IRP can be freed with a single
* free() operation
*
* @return new IRP or NULL on error
*****************************************************************************/
IRP * devredir_irp_clone(IRP *irp)
IRP * devredir_irp_with_pathname_new(const char *pathname)
{
IRP *new_irp;
IRP *prev;
IRP *next;
unsigned int len = g_strlen(pathname);
IRP * irp = devredir_irp_with_pathnamelen_new(len);
if (irp != NULL)
{
g_strcpy(irp->pathname, pathname);
}
if ((new_irp = devredir_irp_new()) == NULL)
return irp;
}
/**
* Create a new IRP with space allocated for a pathname, and append to
* linked list.
*
* Allocation is made in such a way that the IRP can be freed with a single
* free() operation
*
* @return new IRP or NULL on error
*****************************************************************************/
IRP * devredir_irp_with_pathnamelen_new(unsigned int pathnamelen)
{
IRP *irp;
IRP *irp_last;
log_debug("entered");
/* create new IRP with space on end for the pathname and a terminator */
irp = (IRP *)g_malloc(sizeof(IRP) + (pathnamelen + 1), 1);
if (irp == NULL)
{
log_error("system out of memory!");
return NULL;
}
/* save link pointers */
prev = new_irp->prev;
next = new_irp->next;
irp->pathname = (char *)irp + sizeof(IRP); /* Initialise pathname pointer */
/* copy all members */
g_memcpy(new_irp, irp, sizeof(IRP));
/* insert at end of linked list */
if ((irp_last = devredir_irp_get_last()) == NULL)
{
/* list is empty, this is the first entry */
g_irp_head = irp;
}
else
{
irp_last->next = irp;
irp->prev = irp_last;
}
/* restore link pointers */
new_irp->prev = prev;
new_irp->next = next;
return new_irp;
log_debug("new IRP=%p", irp);
return irp;
}
/**

View File

@ -29,11 +29,49 @@
#endif
#include "chansrv_fuse.h"
typedef struct fuse_data FUSE_DATA;
struct fuse_data
/* Opaque data types to us */
typedef struct xfuse_info XFUSE_INFO;
enum irp_lookup_state
{
void *data_ptr;
FUSE_DATA *next;
E_LOOKUP_GET_FH = 0,
E_LOOKUP_CHECK_BASIC,
E_LOOKUP_CHECK_EOF
} ;
enum irp_setattr_state
{
E_SETATTR_GET_FH = 0,
E_SETATTR_CHECK_BASIC,
E_SETATTR_CHECK_EOF
} ;
struct irp_lookup
{
enum irp_lookup_state state; /* Next state to consider */
struct file_attr fattr; /* Attributes to get */
};
struct irp_setattr
{
enum irp_setattr_state state; /* Next state to consider */
tui32 to_set; /* Bit mask for elements in use */
struct file_attr fattr; /* Attributes to set */
};
struct irp_write
{
tui64 offset; /* Offset the write was made at */
};
struct irp_create
{
int creating_dir; /* We're creating a directory */
};
struct irp_rename
{
char *new_name; /* New name for file */
};
/* An I/O Resource Packet to track I/O calls */
@ -46,15 +84,18 @@ struct irp
tui32 DeviceId; /* identifies remote device */
tui32 FileId; /* RDP client provided unique number */
char completion_type; /* describes I/O type */
char pathname[256]; /* absolute pathname */
char *pathname; /* absolute pathname
* Allocate with
* devredir_irp_with_pathname_new() */
union
{
char buf[1024]; /* General character data */
struct file_attr fattr; /* Used to assemble file attributes */
} gen; /* for general use */
int type;
FUSE_DATA *fd_head; /* point to first FUSE opaque object */
FUSE_DATA *fd_tail; /* point to last FUSE opaque object */
struct irp_lookup lookup; /* Used by lookup */
struct irp_setattr setattr; /* Used by setattr */
struct irp_write write; /* Used by write */
struct irp_create create; /* Used by create */
struct irp_rename rename; /* Use by rename */
} gen; /* Additional state data for some ops */
void *fuse_info; /* Fuse info pointer for FUSE calls */
IRP *next; /* point to next IRP */
IRP *prev; /* point to previous IRP */
int scard_index; /* used to smart card to locate dev */
@ -65,7 +106,13 @@ struct irp
};
IRP * devredir_irp_new(void);
IRP * devredir_irp_clone(IRP *irp);
/* As above, but allocates sufficent space for the specified
* pathname, and copies it in to the pathname field */
IRP * devredir_irp_with_pathname_new(const char *pathname);
/* As above, but specifies a pathname length with pathname
* initially set to "". Use if you need to modify the pathname
* significantly */
IRP * devredir_irp_with_pathnamelen_new(unsigned int pathnamelen);
int devredir_irp_delete(IRP *irp);
IRP * devredir_irp_find(tui32 completion_id);
IRP * devredir_irp_find_by_fileid(tui32 FileId);

44
sesman/chansrv/ms-erref.h Normal file
View File

@ -0,0 +1,44 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* MS-ERREF : Definitions from [MS-ERREF]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* References to MS-ERREF are currently correct for v20180912 of that
* document
*/
#if !defined(MS_ERREF_H)
#define MS_ERREF_H
/*
* NTSTATUS codes (section 2.3)
*/
enum NTSTATUS
{
NT_STATUS_SUCCESS = 0x00000000,
NT_STATUS_UNSUCCESSFUL = 0xC0000001,
NT_STATUS_NO_SUCH_FILE = 0xC000000F,
NT_STATUS_ACCESS_DENIED = 0xC0000022,
NT_STATUS_OBJECT_NAME_INVALID = 0xC0000033,
NT_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
NT_STATUS_SHARING_VIOLATION = 0xC0000043,
NT_STATUS_NO_MORE_FILES = 0x80000006
};
#endif /* MS_ERREF_H */

64
sesman/chansrv/ms-fscc.h Normal file
View File

@ -0,0 +1,64 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* MS-FSCC : Definitions from [MS-FSCC]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* References to MS-FSCC are currently correct for v20190923 of that
* document
*/
#if !defined(MS_FSCC_H)
#define MS_FSCC_H
/*
* File system ioctl codes (section 2.3)
*/
#define FSCTL_DELETE_OBJECT_ID 0x900a0
/*
* File information classes (section 2.4)
*/
enum FS_INFORMATION_CLASS
{
FileAllocationInformation = 19, /* Set */
FileBasicInformation = 4, /* Query, Set */
FileBothDirectoryInformation = 3, /* Query */
FileDirectoryInformation = 1, /* Query */
FileDispositionInformation = 13, /* Set */
FileEndOfFileInformation = 20, /* Set */
FileFullDirectoryInformation = 2, /* Query */
FileNamesInformation = 12, /* Query */
FileRenameInformation = 10, /* Set */
FileStandardInformation = 5 /* Query */
};
/*
* Size of structs above without trailing RESERVED fields (MS-RDPEFS
* 2.2.3.3.8)
*/
#define FILE_BASIC_INFORMATION_SIZE 36
#define FILE_STD_INFORMATION_SIZE 22
#define FILE_END_OF_FILE_INFORMATION_SIZE 8
/* Windows file attributes (section 2.6) */
#define W_FILE_ATTRIBUTE_DIRECTORY 0x00000010
#define W_FILE_ATTRIBUTE_READONLY 0x00000001
#define W_FILE_ATTRIBUTE_SYSTEM 0x00000004
#define W_FILE_ATTRIBUTE_NORMAL 0x00000080
#endif /* MS_FSCC_H */

125
sesman/chansrv/ms-rdpefs.h Normal file
View File

@ -0,0 +1,125 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* MS-RDPEFS : Definitions from [MS-RDPEFS]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* References to MS-RDPEFS are currently correct for v20180912 of that
* document
*/
#if !defined(MS_RDPEFS_H)
#define MS_RDPEFS_H
/*
* RDPDR_HEADER definitions (2.2.1.1)
*/
/* device redirector core component; most of the packets in this protocol */
/* are sent under this component ID */
#define RDPDR_CTYP_CORE 0x4472
/* printing component. the packets that use this ID are typically about */
/* printer cache management and identifying XPS printers */
#define RDPDR_CTYP_PRN 0x5052
/* Server Announce Request, as specified in section 2.2.2.2 */
#define PAKID_CORE_SERVER_ANNOUNCE 0x496E
/* Client Announce Reply and Server Client ID Confirm, as specified in */
/* sections 2.2.2.3 and 2.2.2.6. */
#define PAKID_CORE_CLIENTID_CONFIRM 0x4343
/* Client Name Request, as specified in section 2.2.2.4 */
#define PAKID_CORE_CLIENT_NAME 0x434E
/* Client Device List Announce Request, as specified in section 2.2.2.9 */
#define PAKID_CORE_DEVICELIST_ANNOUNCE 0x4441
/* Server Device Announce Response, as specified in section 2.2.2.1 */
#define PAKID_CORE_DEVICE_REPLY 0x6472
/* Device I/O Request, as specified in section 2.2.1.4 */
#define PAKID_CORE_DEVICE_IOREQUEST 0x4952
/* Device I/O Response, as specified in section 2.2.1.5 */
#define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943
/* Server Core Capability Request, as specified in section 2.2.2.7 */
#define PAKID_CORE_SERVER_CAPABILITY 0x5350
/* Client Core Capability Response, as specified in section 2.2.2.8 */
#define PAKID_CORE_CLIENT_CAPABILITY 0x4350
/* Client Drive Device List Remove, as specified in section 2.2.3.2 */
#define PAKID_CORE_DEVICELIST_REMOVE 0x444D
/* Add Printer Cachedata, as specified in [MS-RDPEPC] section 2.2.2.3 */
#define PAKID_PRN_CACHE_DATA 0x5043
/* Server User Logged On, as specified in section 2.2.2.5 */
#define PAKID_CORE_USER_LOGGEDON 0x554C
/* Server Printer Set XPS Mode, as specified in [MS-RDPEPC] section 2.2.2.2 */
#define PAKID_PRN_USING_XPS 0x5543
/*
* Capability header definitions (2.2.1.2)
*/
#define CAP_GENERAL_TYPE 0x0001 /* General cap set - GENERAL_CAPS_SET */
#define CAP_PRINTER_TYPE 0x0002 /* Print cap set - PRINTER_CAPS_SET */
#define CAP_PORT_TYPE 0x0003 /* Port cap set - PORT_CAPS_SET */
#define CAP_DRIVE_TYPE 0x0004 /* Drive cap set - DRIVE_CAPS_SET */
#define CAP_SMARTCARD_TYPE 0x0005 /* Smart card cap set - SMARTCARD_CAPS_SET */
/*
* Device announce header (2.2.1.3)
*/
#define RDPDR_DTYP_SERIAL 0x0001
#define RDPDR_DTYP_PARALLEL 0x0002
#define RDPDR_DTYP_PRINT 0x0004
#define RDPDR_DTYP_FILESYSTEM 0x0008
#define RDPDR_DTYP_SMARTCARD 0x0020
/* Device I/O Request definitions (2.2.1.4) */
/* MajorFunction */
enum IRP_MJ
{
IRP_MJ_CREATE = 0x00000000,
IRP_MJ_CLOSE = 0x00000002,
IRP_MJ_READ = 0x00000003,
IRP_MJ_WRITE = 0x00000004,
IRP_MJ_DEVICE_CONTROL = 0x0000000E,
IRP_MJ_QUERY_VOLUME_INFORMATION = 0x0000000A,
IRP_MJ_SET_VOLUME_INFORMATION = 0x0000000B,
IRP_MJ_QUERY_INFORMATION = 0x00000005,
IRP_MJ_SET_INFORMATION = 0x00000006,
IRP_MJ_DIRECTORY_CONTROL = 0x0000000C,
IRP_MJ_LOCK_CONTROL = 0x00000011
};
/* MinorFunction */
/* Set to zero unless MajorFunction code == IRP_MJ_DIRECTORY_CONTROL */
enum IRP_MN
{
IRP_MN_NONE = 0x00000000, /* Name not in MS docs */
IRP_MN_QUERY_DIRECTORY = 0x00000001,
IRP_MN_NOTIFY_CHANGE_DIRECTORY = 0x00000002
};
#endif /* MS_RDPEFS_H */

79
sesman/chansrv/ms-smb2.h Normal file
View File

@ -0,0 +1,79 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* MS-SMB2 : Definitions from [MS-SMB2]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* References to MS-SMB2 are currently correct for v20190923 of that
* document
*/
#if !defined(MS_SMB2_H)
#define MS_SMB2_H
/* SMB2 CREATE request values (section 2.2.13) */
/*
* ShareAccess Mask. Currently, this is referred
* to in MS-RDPEFS 2.2.1.4.1 as 'SharedAccess' rather than 'ShareAccess'.
*/
#define SA_FILE_SHARE_READ 0x00000001
#define SA_FILE_SHARE_WRITE 0x00000002
#define SA_FILE_SHARE_DELETE 0x00000004
/* CreateDisposition Mask */
#define CD_FILE_SUPERSEDE 0x00000000
#define CD_FILE_OPEN 0x00000001
#define CD_FILE_CREATE 0x00000002
#define CD_FILE_OPEN_IF 0x00000003
#define CD_FILE_OVERWRITE 0x00000004
#define CD_FILE_OVERWRITE_IF 0x00000005
/* CreateOptions Mask */
enum CREATE_OPTIONS
{
CO_FILE_DIRECTORY_FILE = 0x00000001,
CO_FILE_WRITE_THROUGH = 0x00000002,
CO_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020,
CO_FILE_DELETE_ON_CLOSE = 0x00001000
};
/*
* DesiredAccess Mask (section 2.2.13.1.1)
*/
#define DA_FILE_READ_DATA 0x00000001
#define DA_FILE_WRITE_DATA 0x00000002
#define DA_FILE_APPEND_DATA 0x00000004
#define DA_FILE_READ_EA 0x00000008 /* rd extended attributes */
#define DA_FILE_WRITE_EA 0x00000010 /* wr extended attributes */
#define DA_FILE_EXECUTE 0x00000020
#define DA_FILE_READ_ATTRIBUTES 0x00000080
#define DA_FILE_WRITE_ATTRIBUTES 0x00000100
#define DA_DELETE 0x00010000
#define DA_READ_CONTROL 0x00020000 /* rd security descriptor */
#define DA_WRITE_DAC 0x00040000
#define DA_WRITE_OWNER 0x00080000
#define DA_SYNCHRONIZE 0x00100000
#define DA_ACCESS_SYSTEM_SECURITY 0x01000000
#define DA_MAXIMUM_ALLOWED 0x02000000
#define DA_GENERIC_ALL 0x10000000
#define DA_GENERIC_EXECUTE 0x20000000
#define DA_GENERIC_WRITE 0x40000000
#define DA_GENERIC_READ 0x80000000
#endif /* MS_SMB2_H */

View File

@ -871,7 +871,7 @@ scard_make_new_ioctl(IRP *irp, tui32 ioctl)
irp->FileId,
irp->CompletionId,
IRP_MJ_DEVICE_CONTROL,
0);
IRP_MN_NONE);
xstream_wr_u32_le(s, 2048); /* OutputBufferLength */
s_push_layer(s, iso_hdr, 4); /* InputBufferLength - insert later */

View File

@ -105,6 +105,9 @@ param=96
[Chansrv]
; drive redirection, defaults to xrdp_client if not set
FuseMountName=thinclient_drives
; this value allows only the user to acess their own mapped drives.
; Make this more permissive (e.g. 022) if required.
FileUmask=077
[SessionVariables]
PULSE_SCRIPT=@sesmansysconfdir@/pulse/default.pa