From: Volker Lendecke Date: Mon, 5 Dec 2022 11:15:21 +0000 (+0100) Subject: smbd: Add read_symlink_reparse() X-Git-Tag: talloc-2.4.1~154 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=58f7ec12bd46b010f81284bb32f644576a253aef;p=thirdparty%2Fsamba.git smbd: Add read_symlink_reparse() Fake up a symlink reparse point structure from an on-disk reparse point. Turn in-share absolute symlinks into relative ones for the client to properly follow symlinks. Pass on everything else as-is. In particular clients follow symlinks pointing at \\server\share\... Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- diff --git a/source3/smbd/files.c b/source3/smbd/files.c index ac2bdbd4fde..98cd870917b 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -25,6 +25,7 @@ #include "util_tdb.h" #include "lib/util/bitmap.h" #include "lib/util/strv.h" +#include "libcli/smb/reparse_symlink.h" #define FILE_HANDLE_OFFSET 0x1000 @@ -729,6 +730,67 @@ NTSTATUS readlink_talloc( return NT_STATUS_OK; } +NTSTATUS read_symlink_reparse( + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + struct smb_filename *smb_relname, + struct symlink_reparse_struct **_symlink) +{ + struct symlink_reparse_struct *symlink = NULL; + NTSTATUS status; + + symlink = talloc_zero(mem_ctx, struct symlink_reparse_struct); + if (symlink == NULL) { + goto nomem; + } + + status = readlink_talloc( + symlink, dirfsp, smb_relname, &symlink->substitute_name); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("readlink_talloc failed: %s\n", nt_errstr(status)); + goto fail; + } + + if (symlink->substitute_name[0] == '/') { + const char *connectpath = dirfsp->conn->connectpath; + char *abs_target_canon = NULL; + const char *relative = NULL; + bool in_share; + + abs_target_canon = + canonicalize_absolute_path(talloc_tos(), + symlink->substitute_name); + if (abs_target_canon == NULL) { + goto nomem; + } + + in_share = subdir_of(connectpath, + strlen(connectpath), + abs_target_canon, + &relative); + if (in_share) { + TALLOC_FREE(symlink->substitute_name); + symlink->substitute_name = + talloc_strdup(symlink, relative); + if (symlink->substitute_name == NULL) { + goto nomem; + } + } + } + + if (!IS_DIRECTORY_SEP(symlink->substitute_name[0])) { + symlink->flags |= SYMLINK_FLAG_RELATIVE; + } + + *_symlink = symlink; + return NT_STATUS_OK; +nomem: + status = NT_STATUS_NO_MEMORY; +fail: + TALLOC_FREE(symlink); + return status; +} + NTSTATUS openat_pathref_dirfsp_nosymlink( TALLOC_CTX *mem_ctx, struct connection_struct *conn, diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 966a4530c1d..1763a5e0504 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -444,6 +444,14 @@ NTSTATUS readlink_talloc( struct smb_filename *smb_relname, char **_substitute); +struct symlink_reparse_struct; + +NTSTATUS read_symlink_reparse( + TALLOC_CTX *mem_ctx, + struct files_struct *dirfsp, + struct smb_filename *smb_relname, + struct symlink_reparse_struct **_symlink); + void smb_fname_fsp_unlink(struct smb_filename *smb_fname); NTSTATUS move_smb_fname_fsp_link(struct smb_filename *smb_fname_dst,