Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/neutrinolabs/xrdp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/sesman
diff options
context:
space:
mode:
authormatt335672 <30179339+matt335672@users.noreply.github.com>2021-10-25 18:16:54 +0300
committermatt335672 <30179339+matt335672@users.noreply.github.com>2021-10-25 18:16:54 +0300
commitb87b7f9ee8229be8e400a2547aef4fc125d70a7b (patch)
tree135a595ddddc0db0772c27dc85355c89fdb5e59b /sesman
parenta7b48cd1cf41c57b10e744c1c4d28495314eccc3 (diff)
Add xfuse_path_in_xfuse_fs()
Diffstat (limited to 'sesman')
-rw-r--r--sesman/chansrv/chansrv_fuse.c130
-rw-r--r--sesman/chansrv/chansrv_fuse.h9
2 files changed, 137 insertions, 2 deletions
diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c
index 1b3a0f9e..a2ea8d23 100644
--- a/sesman/chansrv/chansrv_fuse.c
+++ b/sesman/chansrv/chansrv_fuse.c
@@ -18,6 +18,11 @@
/* FUSE mount point */
char g_fuse_root_path[256] = "";
+#ifdef XRDP_FUSE
+static const char *g_fuse_root_path_basename; /* See xfuse_path_in_xfuse_fs() */
+static int g_fuse_root_parent_dev; /* Ditto */
+static int g_fuse_root_parent_ino; /* Ditto */
+#endif
char g_fuse_clipboard_path[256] = ""; /* for clipboard use */
#if defined(HAVE_CONFIG_H)
@@ -122,6 +127,11 @@ void xfuse_devredir_cb_rename_file(struct state_rename *fip,
void xfuse_devredir_cb_file_close(struct state_close *fip)
{}
+int xfuse_path_in_xfuse_fs(const char *path)
+{
+ return 0;
+}
+
#else
/******************************************************************************
@@ -324,6 +334,7 @@ static char *g_buffer = 0;
static int g_fd = 0;
static tintptr g_bufsize = 0;
+
/* forward declarations for internal access */
static int xfuse_init_xrdp_fs(void);
static int xfuse_deinit_xrdp_fs(void);
@@ -461,6 +472,7 @@ int
xfuse_init(void)
{
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+ char *p;
/* if already inited, just return */
if (g_xfuse_inited)
@@ -507,16 +519,59 @@ xfuse_init(void)
g_snprintf(g_fuse_root_path, sizeof(g_fuse_root_path), "%s/%s",
g_getenv("HOME"), g_cfg->fuse_mount_name);
}
+
+ /* Remove all trailing '/' from the root path */
+ p = g_fuse_root_path + g_strlen(g_fuse_root_path);
+ while ( p > g_fuse_root_path && *(p - 1) == '/')
+ {
+ --p;
+ *p = '\0';
+ }
+
+ /* This shouldn't happen */
+ if (g_strlen(g_fuse_root_path) == 0)
+ {
+ LOG(LOG_LEVEL_ERROR,
+ "Fuse root path is empty after removing trailing '/'");
+ return -1;
+ }
+
g_snprintf(g_fuse_clipboard_path, 255, "%s/.clipboard", g_fuse_root_path);
+ /* Get the characteristics of the parent directory of the FUSE mount
+ * point. Used by xfuse_path_in_xfuse_fs() */
+ p = (char *)g_strrchr(g_fuse_root_path, '/');
+ if (p != NULL)
+ {
+ /* Temporarily finish the root path at this point */
+ *p = '\0';
+ g_fuse_root_path_basename = p + 1;
+ g_fuse_root_parent_dev = g_file_get_device_number(g_fuse_root_path);
+ g_fuse_root_parent_ino = g_file_get_inode_num(g_fuse_root_path);
+ *p = '/';
+ }
+ else
+ {
+ g_fuse_root_parent_dev = -1;
+ g_fuse_root_parent_ino = -1;
+ }
+
+ if (g_fuse_root_parent_dev == -1 || g_fuse_root_parent_ino == -1)
+ {
+ LOG(LOG_LEVEL_ERROR,
+ "Unable to obtain characteristics of directory containing %s",
+ g_fuse_root_path);
+ return -1;
+ }
+
/* if FUSE mount point does not exist, create it */
if (!g_directory_exist(g_fuse_root_path))
{
(void)g_create_path(g_fuse_root_path);
if (!g_create_dir(g_fuse_root_path))
{
- LOG_DEVEL(LOG_LEVEL_ERROR, "mkdir %s failed. If %s is already mounted, you must "
- "first unmount it", g_fuse_root_path, g_fuse_root_path);
+ LOG(LOG_LEVEL_ERROR, "mkdir %s failed. If %s is already mounted, you must "
+ "first unmount it", g_fuse_root_path, g_fuse_root_path);
return -1;
}
}
@@ -1491,6 +1546,77 @@ void xfuse_devredir_cb_file_close(struct state_close *fip)
free(fip);
}
+/*
+ * Determine is a file is in the FUSE filesystem
+ *
+ * The whole purpose of this function is to avoid deadlocks. If we try
+ * to determine the size (or any other attribute) of a file in the FUSE
+ * filesystem, the kernel will block the calling thread and send a message
+ * to libfuse. Since we're single-threaded, this will result in deadlock.
+ *
+ * Ideally we'd use a stat() of the file to compare with a stat() of
+ * the mountpoint. This won't work however, for the reasons outline above.
+ *
+ * A simple implementation might be to compare the start of the filename
+ * with the FUSE mount point. This will work, but can easily be defeated,
+ * (perhaps unintentionally) by symlinks in the path.
+ *
+ * The approach taken here is to record the basename of the FUSE mount
+ * point directory (e.g. 'thinclient_drives') and look for that in the
+ * passed-in filename as a directory element. If we find it, we look
+ * at the device name and inode number of the parent directory of the
+ * FUSE mount point. If these match we consider the filename to be in
+ * the FUSE filesystem.
+ */
+int xfuse_path_in_xfuse_fs(const char *path)
+{
+ char *wpath = NULL; /* Writeable copy of path */
+ char *p;
+ int blen = g_strlen(g_fuse_root_path_basename);
+ int rv = 0;
+
+ if ((wpath = g_strdup(path)) == NULL)
+ {
+ LOG(LOG_LEVEL_ERROR, "system out of memory");
+ }
+ else
+ {
+ /* Look ahead in the string for the basename of the FUSE mount point */
+ for (p = wpath;
+ (p = g_strstr(p, g_fuse_root_path_basename)) != NULL ;
+ p = p + 1)
+ {
+ /* Is this string preceded by a '/' ? */
+ if (p == wpath || *(p - 1) != '/')
+ {
+ continue;
+ }
+
+ /* Is the string followed by a '/' or '\0' ? We know it's
+ * valid to look ahead this far in the string, as g_strstr()
+ * tells us it is */
+ if (*(p + blen) != '/' && *(p + blen) != '\0')
+ {
+ continue;
+ }
+
+ /* Temporarily terminate the string early, and check the
+ * file system characteristics of the preceding directory */
+ *(p - 1) = '\0';
+
+ if (g_file_get_device_number(wpath) == g_fuse_root_parent_dev &&
+ g_file_get_inode_num(wpath) == g_fuse_root_parent_ino)
+ {
+ rv = 1;
+ break;
+ }
+ *(p - 1) = '/';
+ }
+ g_free(wpath);
+ }
+ return rv;
+}
+
/******************************************************************************
** **
** callbacks for fuse **
diff --git a/sesman/chansrv/chansrv_fuse.h b/sesman/chansrv/chansrv_fuse.h
index 5a125d11..a456bc90 100644
--- a/sesman/chansrv/chansrv_fuse.h
+++ b/sesman/chansrv/chansrv_fuse.h
@@ -114,4 +114,13 @@ void xfuse_devredir_cb_rename_file(struct state_rename *fip,
void xfuse_devredir_cb_file_close(struct state_close *fip);
+/*
+ * Returns true if a filesystem path lies in the FUSE filesystem
+ *
+ * Use to prevent deadlocks. For example, if chansrv tries to open
+ * a file in the FUSE filesystem it will fail, as it will call back
+ * into itself to handle the I/O
+ */
+int xfuse_path_in_xfuse_fs(const char *path);
+
#endif