From 9f35cced6aa5f34b7accfecf9fa751685bf3a690 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 19 Jul 2021 14:52:32 -0700 Subject: [PATCH 1/2] s3: VFS: vfs_streams_depot: Factor out the code that gets the absolute stream rootdir into a function. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14760 Signed-off-by: Jeremy Allison --- source3/modules/vfs_streams_depot.c | 50 +++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c index d9abf1d71b9..d3b511d3132 100644 --- a/source3/modules/vfs_streams_depot.c +++ b/source3/modules/vfs_streams_depot.c @@ -129,6 +129,39 @@ static bool mark_file_valid(vfs_handle_struct *handle, return true; } +/* + * Return the root of the stream directory. Can be + * external to the share definition but by default + * is "handle->conn->connectpath/.streams". + * + * Note that this is an *absolute* path, starting + * with '/', so the dirfsp being used in the + * calls below isn't looked at. + */ + +static char *stream_rootdir(vfs_handle_struct *handle, + TALLOC_CTX *ctx) +{ + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); + char *tmp; + + tmp = talloc_asprintf(ctx, + "%s/.streams", + handle->conn->connectpath); + if (tmp == NULL) { + errno = ENOMEM; + return NULL; + } + + return lp_parm_substituted_string(ctx, + lp_sub, + SNUM(handle->conn), + "streams_depot", + "directory", + tmp); +} + /** * Given an smb_filename, determine the stream directory using the file's * base_name. @@ -137,14 +170,12 @@ static char *stream_dir(vfs_handle_struct *handle, const struct smb_filename *smb_fname, const SMB_STRUCT_STAT *base_sbuf, bool create_it) { - const struct loadparm_substitution *lp_sub = - loadparm_s3_global_substitution(); uint32_t hash; struct smb_filename *smb_fname_hash = NULL; char *result = NULL; SMB_STRUCT_STAT base_sbuf_tmp; + char *tmp = NULL; uint8_t first, second; - char *tmp; char *id_hex; struct file_id id; uint8_t id_buf[16]; @@ -159,17 +190,8 @@ static char *stream_dir(vfs_handle_struct *handle, check_valid = lp_parm_bool(SNUM(handle->conn), "streams_depot", "check_valid", true); - tmp = talloc_asprintf(talloc_tos(), "%s/.streams", - handle->conn->connectpath); - - if (tmp == NULL) { - errno = ENOMEM; - goto fail; - } - - rootdir = lp_parm_substituted_string(talloc_tos(), lp_sub, - SNUM(handle->conn), "streams_depot", "directory", - tmp); + rootdir = stream_rootdir(handle, + talloc_tos()); if (rootdir == NULL) { errno = ENOMEM; goto fail; -- 2.27.0 From 8ba18c60abcfcb00ab9d735266319c178f5ed0c1 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 19 Jul 2021 15:10:41 -0700 Subject: [PATCH 2/2] s3: VFS: streams_depot: Allow "streams directory" outside of share path to work again. As we're dealing with absolute paths here, we just need to temporarily replace the connectpath whilst enumerating streams. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14760 Signed-off-by: Jeremy Allison --- source3/modules/vfs_streams_depot.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c index d3b511d3132..973edeeda24 100644 --- a/source3/modules/vfs_streams_depot.c +++ b/source3/modules/vfs_streams_depot.c @@ -544,6 +544,8 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle, void *private_data) { char *dirname; + char *rootdir = NULL; + char *orig_connectpath = NULL; struct smb_filename *dir_smb_fname = NULL; struct smb_Dir *dir_hnd = NULL; const char *dname = NULL; @@ -576,8 +578,26 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle, return NT_STATUS_NO_MEMORY; } + /* + * For OpenDir to succeed if the stream rootdir is outside + * the share path, we must temporarily swap out the connect + * path for this share. We're dealing with absolute paths + * here so we don't care about chdir calls. + */ + rootdir = stream_rootdir(handle, talloc_tos()); + if (rootdir == NULL) { + TALLOC_FREE(dir_smb_fname); + TALLOC_FREE(dirname); + return NT_STATUS_NO_MEMORY; + } + + orig_connectpath = handle->conn->connectpath; + handle->conn->connectpath = rootdir; + dir_hnd = OpenDir(talloc_tos(), handle->conn, dir_smb_fname, NULL, 0); if (dir_hnd == NULL) { + handle->conn->connectpath = orig_connectpath; + TALLOC_FREE(rootdir); TALLOC_FREE(dir_smb_fname); TALLOC_FREE(dirname); return map_nt_error_from_unix(errno); @@ -600,6 +620,9 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle, TALLOC_FREE(talloced); } + /* Restore the original connectpath. */ + handle->conn->connectpath = orig_connectpath; + TALLOC_FREE(rootdir); TALLOC_FREE(dir_smb_fname); TALLOC_FREE(dir_hnd); -- 2.27.0