From a3d429b4f7bc5d06236c48df7e9b1f770514f7c9 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Tue, 3 Mar 2020 10:02:32 +0000 Subject: [PATCH 1/2] Minor fixes to drive redirection --- common/ms-erref.h | 3 +- sesman/chansrv/chansrv_fuse.c | 54 ++++++++++++++------- sesman/chansrv/chansrv_fuse.h | 1 + sesman/chansrv/chansrv_xfs.c | 4 +- sesman/chansrv/devredir.c | 89 ++++++++++++++++++++--------------- sesman/chansrv/devredir.h | 9 ++-- 6 files changed, 100 insertions(+), 60 deletions(-) diff --git a/common/ms-erref.h b/common/ms-erref.h index 3b1b75e5..394766a1 100644 --- a/common/ms-erref.h +++ b/common/ms-erref.h @@ -36,7 +36,8 @@ enum NTSTATUS STATUS_ACCESS_DENIED = 0xc0000022, STATUS_OBJECT_NAME_INVALID = 0xc0000033, STATUS_OBJECT_NAME_NOT_FOUND = 0xc0000034, - STATUS_SHARING_VIOLATION = 0xc0000043 + STATUS_SHARING_VIOLATION = 0xc0000043, + STATUS_NOT_SUPPORTED = 0xc00000bb }; #endif /* MS_ERREF_H */ diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index b57cc662..178d1ded 100644 --- a/sesman/chansrv/chansrv_fuse.c +++ b/sesman/chansrv/chansrv_fuse.c @@ -78,6 +78,7 @@ void xfuse_devredir_cb_open_file(struct state_open *fip, tui32 DeviceId, tui32 FileId) {} void xfuse_devredir_cb_read_file(struct state_read *fip, + enum NTSTATUS IoStatus, const char *buf, size_t length) {} void xfuse_devredir_cb_write_file( @@ -1313,9 +1314,18 @@ void xfuse_devredir_cb_open_file(struct state_open *fip, } void xfuse_devredir_cb_read_file(struct state_read *fip, + enum NTSTATUS IoStatus, const char *buf, size_t length) { - fuse_reply_buf(fip->req, buf, length); + if (IoStatus != STATUS_SUCCESS) + { + log_error("Read NTSTATUS is %d", (int) IoStatus); + fuse_reply_err(fip->req, EIO); + } + else + { + fuse_reply_buf(fip->req, buf, length); + } free(fip); } @@ -1679,7 +1689,7 @@ static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent, //XFUSE_HANDLE *fh; log_debug("LK_TODO: this is still a TODO"); - fuse_reply_err(req, EINVAL); + fuse_reply_err(req, EROFS); } else { @@ -1744,26 +1754,26 @@ static void xfuse_cb_rename(fuse_req_t req, else if (!(new_parent_xinode = xfs_get(g_xfs, new_parent))) { log_error("inode %ld is not valid", new_parent); - fuse_reply_err(req, EINVAL); + fuse_reply_err(req, ENOENT); } else if (!xfs_check_move_entry(g_xfs, old_xinode->inum, new_parent, new_name)) { + /* Catchall -see rename(2). Fix when logging is improved */ fuse_reply_err(req, EINVAL); } else if (new_parent_xinode->device_id != old_xinode->device_id) { - log_error("rename across file systems not supported"); - fuse_reply_err(req, EINVAL); + fuse_reply_err(req, EXDEV); } else if (old_xinode->device_id == 0) { /* specified file is a local resource */ log_debug("LK_TODO: this is still a TODO"); - fuse_reply_err(req, EINVAL); + fuse_reply_err(req, EROFS); } else @@ -1853,20 +1863,25 @@ static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent, } /* is parent inode valid? */ - if (parent == FUSE_ROOT_ID || - (xinode = xfs_get(g_xfs, parent)) == NULL || - (xinode->mode & S_IFDIR) == 0) + if (parent == FUSE_ROOT_ID) + { + fuse_reply_err(req, EROFS); + } + else if ((xinode = xfs_get(g_xfs, parent)) == NULL) { - log_error("inode %ld is not valid", parent); fuse_reply_err(req, ENOENT); } + else if ((xinode->mode & S_IFDIR) == 0) + { + fuse_reply_err(req, ENOTDIR); + } else if (xinode->device_id == 0) { /* specified file is a local resource */ //XFUSE_HANDLE *fh; log_debug("LK_TODO: this is still a TODO"); - fuse_reply_err(req, EINVAL); + fuse_reply_err(req, EROFS); } else { @@ -1948,10 +1963,17 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, else if (xinode->device_id == 0) { /* specified file is a local resource */ - XFUSE_HANDLE *fh = g_new0(XFUSE_HANDLE, 1); - fh->is_loc_resource = 1; - fi->fh = (tintptr) fh; - fuse_reply_open(req, fi); + if ((fi->flags & O_ACCMODE) != O_RDONLY) + { + fuse_reply_err(req, EROFS); + } + else + { + XFUSE_HANDLE *fh = g_new0(XFUSE_HANDLE, 1); + fh->is_loc_resource = 1; + fi->fh = (tintptr) fh; + fuse_reply_open(req, fi); + } } else { @@ -2153,7 +2175,7 @@ static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf, { /* target file is in .clipboard dir */ log_debug("THIS IS STILL A TODO!"); - fuse_reply_err(req, EINVAL); + fuse_reply_err(req, EROFS); } else { diff --git a/sesman/chansrv/chansrv_fuse.h b/sesman/chansrv/chansrv_fuse.h index a692dcdd..abd68343 100644 --- a/sesman/chansrv/chansrv_fuse.h +++ b/sesman/chansrv/chansrv_fuse.h @@ -98,6 +98,7 @@ void xfuse_devredir_cb_open_file(struct state_open *fip, tui32 DeviceId, tui32 FileId); void xfuse_devredir_cb_read_file(struct state_read *fip, + enum NTSTATUS IoStatus, const char *buf, size_t length); void xfuse_devredir_cb_write_file( struct state_write *fip, diff --git a/sesman/chansrv/chansrv_xfs.c b/sesman/chansrv/chansrv_xfs.c index feff7e2b..a5f009d2 100644 --- a/sesman/chansrv/chansrv_xfs.c +++ b/sesman/chansrv/chansrv_xfs.c @@ -565,7 +565,7 @@ xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum) */ size_t len = 0; XFS_INODE_ALL *p; - for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent) + for (p = xino ; p && p->pub.inum != FUSE_ROOT_ID ; p = p->parent) { len += strlen(p->pub.name); ++len; /* Allow for '/' prefix */ @@ -578,7 +578,7 @@ xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum) char *end = result + len; *end = '\0'; - for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent) + for (p = xino ; p && p->pub.inum != FUSE_ROOT_ID ; p = p->parent) { len = strlen(p->pub.name); end -= (len + 1); diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index 6455746b..806d9c06 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -560,7 +560,8 @@ devredir_send_server_user_logged_on(void) } static void -devredir_send_server_device_announce_resp(tui32 device_id) +devredir_send_server_device_announce_resp(tui32 device_id, + enum NTSTATUS result_code) { struct stream *s; int bytes; @@ -571,7 +572,7 @@ devredir_send_server_device_announce_resp(tui32 device_id) xstream_wr_u16_le(s, RDPDR_CTYP_CORE); xstream_wr_u16_le(s, PAKID_CORE_DEVICE_REPLY); xstream_wr_u32_le(s, device_id); - xstream_wr_u32_le(s, 0); /* ResultCode */ + xstream_wr_u32_le(s, (tui32)result_code); /* send to client */ bytes = xstream_len(s); @@ -811,6 +812,7 @@ devredir_proc_client_devlist_announce_req(struct stream *s) tui32 device_type; tui32 device_data_len; char preferred_dos_name[9]; + enum NTSTATUS response_status; /* get number of devices being announced */ xstream_rd_u32_le(s, device_count); @@ -821,19 +823,20 @@ devredir_proc_client_devlist_announce_req(struct stream *s) { xstream_rd_u32_le(s, device_type); xstream_rd_u32_le(s, g_device_id); + /* get preferred DOS name + * DOS names that are 8 chars long are not NULL terminated */ + for (j = 0; j < 8; j++) + { + preferred_dos_name[j] = *s->p++; + } + preferred_dos_name[8] = 0; + + /* Assume this device isn't supported by us */ + response_status = STATUS_NOT_SUPPORTED; switch (device_type) { case RDPDR_DTYP_FILESYSTEM: - /* get preferred DOS name */ - for (j = 0; j < 8; j++) - { - preferred_dos_name[j] = *s->p++; - } - - /* DOS names that are 8 chars long are not NULL terminated */ - preferred_dos_name[8] = 0; - /* get device data len */ xstream_rd_u32_le(s, device_data_len); if (device_data_len) @@ -847,7 +850,7 @@ devredir_proc_client_devlist_announce_req(struct stream *s) preferred_dos_name, device_data_len, g_full_name_for_filesystem); - devredir_send_server_device_announce_resp(g_device_id); + response_status = STATUS_SUCCESS; /* create share directory in xrdp file system; */ /* think of this as the mount point for this share */ @@ -855,31 +858,44 @@ devredir_proc_client_devlist_announce_req(struct stream *s) break; case RDPDR_DTYP_SMARTCARD: - /* get preferred DOS name */ - for (j = 0; j < 8; j++) - { - preferred_dos_name[j] = *s->p++; - } - - /* DOS names that are 8 chars long are not NULL terminated */ - preferred_dos_name[8] = 0; - /* for smart cards, device data len always 0 */ log_debug("device_type=SMARTCARD device_id=0x%x dosname=%s", g_device_id, preferred_dos_name); - devredir_send_server_device_announce_resp(g_device_id); + response_status = STATUS_SUCCESS; + scard_device_announce(g_device_id); break; - /* we don't yet support these devices */ case RDPDR_DTYP_SERIAL: + log_debug( + "device_type=SERIAL device_id=0x%x dosname=%s", + g_device_id, preferred_dos_name); + break; + case RDPDR_DTYP_PARALLEL: + log_debug( + "device_type=PARALLEL device_id=0x%x dosname=%s", + g_device_id, preferred_dos_name); + break; + case RDPDR_DTYP_PRINT: - log_debug("unsupported dev: 0x%x", device_type); + log_debug( + "device_type=PRINT device_id=0x%x dosname=%s", + g_device_id, preferred_dos_name); + break; + + default: + log_debug( + "device_type=UNKNOWN device_id=0x%x dosname=%s", + g_device_id, preferred_dos_name); break; } + + /* Tell the client wheth or not we're supporting this one */ + devredir_send_server_device_announce_resp(g_device_id, + response_status); } } @@ -993,6 +1009,7 @@ devredir_proc_device_iocompletion(struct stream *s) case CID_READ: xstream_rd_u32_le(s, Length); xfuse_devredir_cb_read_file((struct state_read *) irp->fuse_info, + IoStatus, s->p, Length); devredir_irp_delete(irp); break; @@ -1511,10 +1528,10 @@ devredir_rmdir_or_file(struct state_remove *fusep, tui32 device_id, /** * Read data from previously opened file * - * @return 0 on success, -1 on failure + * Errors are reported via xfuse_devredir_cb_read_file() *****************************************************************************/ -int +void devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId, tui32 Length, tui64 Offset) { @@ -1522,7 +1539,6 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId, IRP *irp; IRP *new_irp; int bytes; - int rval = -1; xstream_new(s, 1024); @@ -1530,14 +1546,14 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId, if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) { log_error("no IRP found with FileId = %d", FileId); - xfuse_devredir_cb_read_file(fusep, NULL, 0); + xfuse_devredir_cb_read_file(fusep, STATUS_UNSUCCESSFUL, NULL, 0); xstream_free(s); } /* create a new IRP for this request */ else if ((new_irp = devredir_irp_new()) == NULL) { /* system out of memory */ - xfuse_devredir_cb_read_file(fusep, NULL, 0); + xfuse_devredir_cb_read_file(fusep, STATUS_UNSUCCESSFUL, NULL, 0); xstream_free(s); } else @@ -1563,13 +1579,16 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId, bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); - rval = 0; } - - return rval; } -int +/** + * Read data from previously opened file + * + * Errors are reported via xfuse_devredir_cb_write_file() + *****************************************************************************/ + +void devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId, const char *buf, int Length, tui64 Offset) { @@ -1577,7 +1596,6 @@ devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId, IRP *irp; IRP *new_irp; int bytes; - int rval = -1; log_debug("DeviceId=%d FileId=%d Length=%d Offset=%lld", DeviceId, FileId, Length, (long long)Offset); @@ -1625,10 +1643,7 @@ devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId, bytes = xstream_len(s); send_channel_data(g_rdpdr_chan_id, s->data, bytes); xstream_free(s); - rval = 0; } - - return rval; } diff --git a/sesman/chansrv/devredir.h b/sesman/chansrv/devredir.h index 04483753..7ad13745 100644 --- a/sesman/chansrv/devredir.h +++ b/sesman/chansrv/devredir.h @@ -78,12 +78,13 @@ int devredir_file_open(struct state_open *fusep, tui32 device_id, 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); +void +devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId, + tui32 Length, tui64 Offset); -int +void devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId, - const char *buf, int Length, tui64 Offset); + const char *buf, int Length, tui64 Offset); int devredir_file_rename( struct state_rename *fusep, tui32 device_id, From a2266f23f61781d45b2d4a8dc6e19a3d6d00e6a9 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Tue, 3 Mar 2020 16:16:09 +0000 Subject: [PATCH 2/2] Allow a redirected drive device_id to be zero (Guacamole support) --- sesman/chansrv/chansrv_fuse.c | 22 ++++++++++-------- sesman/chansrv/chansrv_xfs.c | 43 +++++++++++++++++++---------------- sesman/chansrv/chansrv_xfs.h | 13 ++++------- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index 178d1ded..62ee050a 100644 --- a/sesman/chansrv/chansrv_fuse.c +++ b/sesman/chansrv/chansrv_fuse.c @@ -638,6 +638,7 @@ int xfuse_create_share(tui32 device_id, const char *dirname) } else { + xinode->is_redirected = 1; xinode->device_id = device_id; result = 0; } @@ -654,7 +655,7 @@ int xfuse_create_share(tui32 device_id, const char *dirname) void xfuse_delete_share(tui32 device_id) { - xfs_delete_entries_with_device_id(g_xfs, device_id); + xfs_delete_redirected_entries_with_device_id(g_xfs, device_id); } /** @@ -1448,7 +1449,7 @@ static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) } else { - if (parent_xinode->device_id == 0) + if (!parent_xinode->is_redirected) { /* File cannot be remote - we either know about it or we don't */ if ((xinode = xfs_lookup_in_dir(g_xfs, parent, name)) != NULL) @@ -1683,7 +1684,7 @@ static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent, fuse_reply_err(req, ENOTEMPTY); } - else if (xinode->device_id == 0) + else if (!xinode->is_redirected) { /* specified file is a local resource */ //XFUSE_HANDLE *fh; @@ -1764,12 +1765,13 @@ static void xfuse_cb_rename(fuse_req_t req, fuse_reply_err(req, EINVAL); } - else if (new_parent_xinode->device_id != old_xinode->device_id) + else if (new_parent_xinode->is_redirected != old_xinode->is_redirected || + new_parent_xinode->device_id != old_xinode->device_id) { fuse_reply_err(req, EXDEV); } - else if (old_xinode->device_id == 0) + else if (!old_xinode->is_redirected) { /* specified file is a local resource */ log_debug("LK_TODO: this is still a TODO"); @@ -1875,7 +1877,7 @@ static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent, { fuse_reply_err(req, ENOTDIR); } - else if (xinode->device_id == 0) + else if (!xinode->is_redirected) { /* specified file is a local resource */ //XFUSE_HANDLE *fh; @@ -1960,7 +1962,7 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, log_debug("Invalid access mode specified"); fuse_reply_err(req, EINVAL); } - else if (xinode->device_id == 0) + else if (!xinode->is_redirected) { /* specified file is a local resource */ if ((fi->flags & O_ACCMODE) != O_RDONLY) @@ -2039,7 +2041,7 @@ static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct log_error("inode %ld is not valid", ino); fuse_reply_err(req, ENOENT); } - else if (xinode->device_id == 0) + else if (!xinode->is_redirected) { /* specified file is a local resource */ fuse_reply_err(req, 0); @@ -2305,7 +2307,7 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, /* No changes have been made */ make_fuse_attr_reply(req, xinode); } - else if (xinode->device_id == 0) + else if (!xinode->is_redirected) { /* Update the local fs */ update_inode_file_attributes(&attrs, change_mask, xinode); @@ -2371,7 +2373,7 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, log_error("inode %ld is not valid", ino); fuse_reply_err(req, ENOENT); } - else if (xinode->device_id == 0) + else if (!xinode->is_redirected) { if ((fi->fh = (tintptr) xfs_opendir(g_xfs, ino)) == 0) { diff --git a/sesman/chansrv/chansrv_xfs.c b/sesman/chansrv/chansrv_xfs.c index a5f009d2..5e75650c 100644 --- a/sesman/chansrv/chansrv_xfs.c +++ b/sesman/chansrv/chansrv_xfs.c @@ -344,6 +344,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid) xino1->pub.ctime = xino1->pub.atime; strcpy(xino1->pub.name, "."); xino1->pub.generation = xfs->generation; + xino1->pub.is_redirected = 0; xino1->pub.device_id = 0; /* @@ -365,6 +366,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid) xino2->pub.ctime = xino2->pub.atime; strcpy(xino2->pub.name, ".delete-pending"); xino2->pub.generation = xfs->generation; + xino2->pub.is_redirected = 0; xino2->pub.device_id = 0; xino2->parent = NULL; @@ -469,6 +471,7 @@ xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum, xino->pub.ctime = xino->pub.atime; strcpy(xino->pub.name, name); xino->pub.generation = xfs->generation; + xino->pub.is_redirected = parent->pub.is_redirected; xino->pub.device_id = parent->pub.device_id; xino->pub.lindex = 0; @@ -816,35 +819,35 @@ xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum) /* ------------------------------------------------------------------------ */ void -xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id) +xfs_delete_redirected_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) { - /* 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.is_redirected != 0 && + xino->pub.device_id == device_id && + (xino->pub.mode & S_IFREG) != 0) { - if ((xino = xfs->inode_table[inum]) != NULL && - xino->pub.device_id == device_id && - (xino->pub.mode & S_IFREG) != 0) - { - xino->open_count = 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) + /* 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.is_redirected != 0 && + xino->pub.device_id == device_id) { - if ((xino = xfs->inode_table[inum]) != NULL && - xino->pub.device_id == device_id) - { - xfs_remove_entry(xfs, xino->pub.inum); - } + xfs_remove_entry(xfs, xino->pub.inum); } } } diff --git a/sesman/chansrv/chansrv_xfs.h b/sesman/chansrv/chansrv_xfs.h index 17dc7b4f..76fa1682 100644 --- a/sesman/chansrv/chansrv_xfs.h +++ b/sesman/chansrv/chansrv_xfs.h @@ -49,9 +49,8 @@ typedef struct xfs_inode 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 */ + char is_redirected; /* file is on redirected device */ + tui32 device_id; /* device ID of redirected device */ int lindex; /* used in clipboard operations */ } XFS_INODE; @@ -271,17 +270,15 @@ unsigned int xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum); /* - * Deletes all entries with the matching device id + * Deletes all redirected 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); +xfs_delete_redirected_entries_with_device_id(struct xfs_fs *xfs, + tui32 device_id); /* * Check an entry move will be successful