mirror of
https://github.com/samba-team/samba.git
synced 2025-01-27 14:04:05 +03:00
smbd: Add get_real_filename_at()
Make get_real_filename() a wrapper. Right now shadow_copy2 does a fallback to do get_real_filename() on the twrp=0 tree in case of snapdirseverywhere because snapdirs can be somewhere deep in the tree, and doing that correctly would be a full-tree walk. I'd say that snapdirseverywhere is impossible to implement if you want symlink safety, i.e. careful top-down tree traversal together with snapdirseverywhere. If you have snapdirseverywhere you need to pass down the full path very deep down, which contradicts our fd-based approach we want to take. Also, I believe that our test does not 100% correctly reflect what actually is there: My understanding is that if you activate snapdirseverywhere for example in GPFS, you see all snapshots at every level (this would need to be verified). Our test does something more nasty: It creates and tests a specific snapshot only at one place deep in the directory hierarchy, which makes it impossible to find without the full path. This is all a big mess, but for now we need to deal with it. This adds the twrp=0 fallback to core smbd, but I don't see any other way to do that properly. And I do want a fd-based getrealfilename.... Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
This commit is contained in:
parent
dcdc258509
commit
c4d4fa68d6
@ -1680,32 +1680,26 @@ NTSTATUS get_real_filename_full_scan(connection_struct *conn,
|
||||
fallback.
|
||||
****************************************************************************/
|
||||
|
||||
static NTSTATUS get_real_filename(connection_struct *conn,
|
||||
struct smb_filename *path,
|
||||
const char *name,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
char **found_name)
|
||||
static NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
|
||||
const char *name,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
char **found_name)
|
||||
{
|
||||
struct connection_struct *conn = dirfsp->conn;
|
||||
NTSTATUS status;
|
||||
bool mangled;
|
||||
|
||||
mangled = mangle_is_mangled(name, conn->params);
|
||||
|
||||
if (mangled) {
|
||||
return get_real_filename_full_scan(conn,
|
||||
path->base_name,
|
||||
name,
|
||||
mangled,
|
||||
mem_ctx,
|
||||
found_name);
|
||||
status = get_real_filename_full_scan_at(
|
||||
dirfsp, name, mangled, mem_ctx, found_name);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Try the vfs first to take advantage of case-insensitive stat. */
|
||||
status = SMB_VFS_GET_REAL_FILENAME(conn,
|
||||
path,
|
||||
name,
|
||||
mem_ctx,
|
||||
found_name);
|
||||
status = SMB_VFS_GET_REAL_FILENAME_AT(
|
||||
dirfsp->conn, dirfsp, name, mem_ctx, found_name);
|
||||
|
||||
/*
|
||||
* If the case-insensitive stat was successful, or returned an error
|
||||
@ -1717,12 +1711,70 @@ static NTSTATUS get_real_filename(connection_struct *conn,
|
||||
return status;
|
||||
}
|
||||
|
||||
return get_real_filename_full_scan(conn,
|
||||
path->base_name,
|
||||
name,
|
||||
mangled,
|
||||
mem_ctx,
|
||||
found_name);
|
||||
status = get_real_filename_full_scan_at(
|
||||
dirfsp, name, mangled, mem_ctx, found_name);
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS get_real_filename(connection_struct *conn,
|
||||
struct smb_filename *path,
|
||||
const char *name,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
char **found_name)
|
||||
{
|
||||
struct smb_filename *smb_dname = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
smb_dname = cp_smb_filename_nostream(talloc_tos(), path);
|
||||
if (smb_dname == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
again:
|
||||
status = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
|
||||
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
|
||||
S_ISLNK(smb_dname->st.st_ex_mode)) {
|
||||
status = NT_STATUS_STOPPED_ON_SYMLINK;
|
||||
}
|
||||
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
|
||||
(smb_dname->twrp != 0)) {
|
||||
/*
|
||||
* Retry looking at the non-snapshot path, copying the
|
||||
* fallback mechanism from vfs_shadow_copy2.c when
|
||||
* shadow_copy2_convert() fails. This path-based
|
||||
* routine get_real_filename() should go away and be
|
||||
* replaced with a fd-based one, so spoiling it with a
|
||||
* shadow_copy2 specific mechanism should not be too
|
||||
* bad.
|
||||
*/
|
||||
smb_dname->twrp = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("openat_pathref_fsp(%s) failed: %s\n",
|
||||
smb_fname_str_dbg(smb_dname),
|
||||
nt_errstr(status));
|
||||
|
||||
/*
|
||||
* ENOTDIR and ELOOP both map to
|
||||
* NT_STATUS_OBJECT_PATH_NOT_FOUND in the filename
|
||||
* walk.
|
||||
*/
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY) ||
|
||||
NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
|
||||
status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = get_real_filename_at(
|
||||
smb_dname->fsp, name, mem_ctx, found_name);
|
||||
TALLOC_FREE(smb_dname);
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
|
||||
|
Loading…
x
Reference in New Issue
Block a user