]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
smbd: Add read_symlink_reparse()
authorVolker Lendecke <vl@samba.org>
Mon, 5 Dec 2022 11:15:21 +0000 (12:15 +0100)
committerVolker Lendecke <vl@samba.org>
Fri, 30 Jun 2023 10:42:36 +0000 (10:42 +0000)
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 <vl@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/smbd/files.c
source3/smbd/proto.h

index ac2bdbd4fde1465487286e53fe789225c3a6693e..98cd870917b01def94c3a900d748f425f4afd535 100644 (file)
@@ -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,
index 966a4530c1dafa94309d74f299ff7e2b47209c13..1763a5e050412a617786a833db4f84e24435b5c7 100644 (file)
@@ -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,