1
0
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:
Volker Lendecke 2022-03-13 16:31:20 +01:00 committed by Ralph Boehme
parent dcdc258509
commit c4d4fa68d6

View File

@ -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,